#include  "KgGlobalData.h"
#include  <QSettings>
#include  <QTime>
#include  <QCoreApplication>
#include  <QProcess>
#include  <QDir>
#include  <QSqlDatabase>
#include  <QSqlQuery>
#include  <QDir>
#include  <QDebug>
#include  "rtdb.h"
#include <QSqlQuery> 
#include <QSqlError>
#include <QTextCodec>
#include "dryctrlthread.h"

//extern unsigned char  g_DIState;
//extern unsigned char  g_DOState;
//extern int      g_bReadDiFlag;
//extern int      g_bReadDoFlag; 
//extern quint16  g_connFailedCount; // 通迅故障计时，通迅正常时清0

// 获取DI索引号字符串,从1开始编号
QString getDiName(const QList<DI_STU>& diList)
{   
	QString strName;
	for(int i = 0; i < diList.size(); ++i)
	{
		if (i > 0)
		{
			strName += ",";
		}
		strName += QString("%1").arg(1+diList[i].diIndex);
	}

	if (0 == diList.size())
	{
		strName = "null";
	}
	
	return strName;
}

QString getDoName(const QList<int>& doList)
{   
	QString strName;
	for(int i = 0; i < doList.size(); ++i)
	{
		if (i > 0)
		{
			strName += ",";
		}
		strName += QString("%1").arg(1+doList[i]);
	}

	if (0 == doList.size())
	{
		strName = "null";
	}
	
	return strName;
}

KgGlobalData::KgGlobalData(void)
{
}

KgGlobalData::~KgGlobalData(void)
{
}

QString KgGlobalData::ms_comDevName = QString();
CRTDB* KgGlobalData::ms_pRTDB = NULL;
CBattStack* KgGlobalData::ms_pStack = NULL;
CIOModule *KgGlobalData::ms_pIOModule = NULL;
	
int KgGlobalData::ms_textCode = 0;
int KgGlobalData::ms_hardwareOemID = 0;
int KgGlobalData::ms_zz404D_addr = 0;
int KgGlobalData::ms_hzEnabled = 0;
int KgGlobalData::ms_faultTkEnabled = 0;
int KgGlobalData::ms_emgTkEnabled = 0;
int KgGlobalData::ms_waterTkEnabled = 0;
int KgGlobalData::ms_confSwitchEnabled = 0;
int KgGlobalData::ms_execFltkFirst = 0;
int KgGlobalData::ms_xfWarnFzEnabled = 0;
int KgGlobalData::ms_xfAlarmFzEnabled = 0;
int KgGlobalData::ms_waterAlarmFzEnabled = 0;
int KgGlobalData::ms_ctrlConfSwitchCount = 0;
int KgGlobalData::ms_devNo = 0;

QString KgGlobalData::m_strDriver=QString();      // DB Information
QString KgGlobalData::m_strIP=QString(); 
ushort  KgGlobalData::m_usPort=0; 
QString KgGlobalData::m_strDBName=QString(); 
QString KgGlobalData::m_strUserName=QString(); 
QString KgGlobalData::m_strPwd=QString();	

int KgGlobalData::ms_installBankNum = 0;//电池组总数
int KgGlobalData::ms_bankNumInStack = 0;// 堆管辖的电池组总数
//QList<BattGroupPara> KgGlobalData::ms_batGroupList;//电池组参数列表
//QList<BattStackPara> KgGlobalData::ms_batStackList;//电池堆参数列表

float KgGlobalData::ms_rwTimeoutSec = 0; // IO模块读写超时时间，单位：秒
float KgGlobalData::ms_tkDelayTime = 0;	 // 控制合闸分闸时，延时时间，单位：秒
int  KgGlobalData::ms_saveHlkgLog = 0;
int  KgGlobalData::ms_devDoCount = 0;		 // ZZ-IO的输出干结点总个数
int  KgGlobalData::ms_devDiCount = 0;		 // ZZ-IO的输入干结点总个数
int  KgGlobalData::ms_bcDiCount = 0;
int  KgGlobalData::ms_bcDoCount = 0;
int  KgGlobalData::ms_diStartRegAddr = 0;    // DI起始寄存器地址
int  KgGlobalData::ms_doStartRegAddr = 0;    // DO起始寄存器地址
int  KgGlobalData::ms_connTimeoutCount = 0;
QList<int> KgGlobalData::ms_diAlarmVals;
//int  KgGlobalData::ms_reverseOrder = 0;

HLKGStrategy KgGlobalData::ms_hlkgStrategy;  // 汇流开关配置策略
XFStrategy KgGlobalData::ms_xfStrategy; 	 // 消防配置策略
XFStrategy KgGlobalData::ms_xfSprayStrategy;// 消防喷洒配置策略 
XFStrategy KgGlobalData::ms_xfFaultStrategy;// 消防故障配置策略
XFStrategy KgGlobalData::ms_xfManuAutoStrategy;// 消防手动/自动配置策略
XFStrategy KgGlobalData::ms_elecPowerOffStrategy;// 市电断电
XFStrategy KgGlobalData::ms_waterStrategy; 	 // 水浸配置策略
XFStrategy KgGlobalData::ms_tdStrategy;	     // 防雷配置策略
XFStrategy KgGlobalData::ms_emgStopStrategy; // 急停配置策略
XFStrategy KgGlobalData::ms_waterStrategySec;  // #2水浸配置策略
XFStrategy KgGlobalData::ms_tdStrategySec;	   // #2防雷配置策略
XFStrategy KgGlobalData::ms_emgStopStrategySec;// #2急停配置策略
XFStrategy KgGlobalData::ms_bmsLocalStrategy; // BMS就地配置策略
XFStrategy KgGlobalData::ms_bmsRemmoteStrategy;// BMS远方配置策略
XFStrategy KgGlobalData::ms_acFaultStrategy;   // 空调机组故障策略
XFStrategy KgGlobalData::ms_lqFaultStrategy;   // 液冷机组故障策略

XFStrategy KgGlobalData::ms_combusGasStrategy;// 可燃气体配置策略
XFStrategy KgGlobalData::ms_fuseStrategy;
XFStrategy KgGlobalData::ms_xfMotionStrategy;
XFStrategy KgGlobalData::ms_xfWarmStrategy;
XFStrategy KgGlobalData::ms_isolSwitchStrategy;  // 隔离开关策略
XFStrategy KgGlobalData::ms_mainSwitchStrategy;

XFStrategy KgGlobalData::ms_upsAlmStrategy;    // UPS配置策略 
XFStrategy KgGlobalData::ms_doorAlmStrategy;   // 门禁配置策略 
XFStrategy KgGlobalData::ms_doorAlmStrategySec; // 门禁告警配置策略
XFStrategy KgGlobalData::ms_resStrategy[RES_STRATEGY_COUNT]; // 备用策略 // added 2023-8-19

QList<DOStrategy> KgGlobalData::ms_gzCtrlList;   // 故障动作干结点列表
QList<DOStrategy> KgGlobalData::ms_alarmCtrlList;// 告警干结点列表
QList<DOStrategy> KgGlobalData::ms_phbChgList;   // 禁充干结点列表
QList<DOStrategy> KgGlobalData::ms_phbDischgList;// 禁放干结点列表
QList<DOStrategy> KgGlobalData::ms_runCtrlList;  // 运行干结点列表
QList<DOStrategy> KgGlobalData::ms_allLightCtrlList; // 常亮灯列表
QList<DOStrategy> KgGlobalData::ms_chgDriveList;  // 充电驱动干结点列表 // added 2021-9-9
QList<DOStrategy> KgGlobalData::ms_dchgDriveList; // 放电驱动干结点列表
QList<DOStrategy> KgGlobalData::ms_fanDriveList; // 风扇驱动干结点列表
QList<DOStrategy> KgGlobalData::ms_bmsEmsCommFaultList;// BMS-EMS通信故障干结点列表
QList<DOStrategy> KgGlobalData::ms_bwGzCtrlList; // 并网故障干节点列表
QList<DI_STU>     KgGlobalData::ms_bcDiList;
QList<DOStrategy> KgGlobalData::ms_bcDoList;
int KgGlobalData::ms_diIndexChgDrive = 999;   // 充电接触器反馈
int KgGlobalData::ms_diIndexDchgDrive = 999;  // 放电接触器反馈
int KgGlobalData::ms_enabled485Alarm = 0; 

int KgGlobalData::ms_isOutputLog = 0;
int KgGlobalData::ms_isSaveDetaiLog = 0;
int KgGlobalData::ms_closeFanDelayTime = 0;
// KgLogFile KgGlobalData::ms_logFile;
DryData KgGlobalData::ms_dryData;
DryData KgGlobalData::ms_drySecData;
DryCtrlThread* KgGlobalData::ms_dryThd;
QString KgGlobalData::ms_IOConfigStr;
//int KgGlobalData::ms_hasUpsDryNode = 0;
int KgGlobalData::ms_openFanTemp = 0;
unsigned int KgGlobalData::ms_keepRegCtrlPos = 0;
KgLogFile KgGlobalData::ms_logFile;
KgLogFile KgGlobalData::ms_bclogFile;
QSqlDatabase g_db;

int KgGlobalData::readConfig()//读取参数配置
{
	int i;
	int temp;
	//KgGlobalData::ms_xfStrategy.diIndex = 999; 		// 设置为无效值
	//KgGlobalData::ms_tdStrategy.diIndex = 999;		// 设置为无效值
	//KgGlobalData::ms_emgStopStrategy.diIndex = 999;// 设置为无效值
	//KgGlobalData::ms_isOutputLog = 0;
	/*
	if (1 == KgGlobalData::ms_isOutputLog)//输出日志
	{
		QDir dir;
		dir.mkdir("/bams/log");
		QString   logFileName = QString("/bams/log/dryctrl.log") ;
		QFile file(logFileName);
		file.remove();
	
		KgGlobalData::ms_logFile.createlogfile(logFileName);
	}
	else
	{
		;
	}	
	*/
	// memset(&KgGlobalData::ms_hlkgStrategy, 0, sizeof(HLKGStrategy)); // 不能清0，里面有QList<>,否则运行会报段错误 2021-10-07
	// KgGlobalData::ms_hlkgStrategy.diCfg.diIndex = 999; 	// 设置为无效值
	// KgGlobalData::ms_hlkgStrategy.fzDoIndex = 999;	// 设置为无效值
	// KgGlobalData::ms_hlkgStrategy.hzDoIndex = 999;	// 设置为无效值
	KgGlobalData::ms_hlkgStrategy.diCfgList.clear();
	KgGlobalData::ms_hlkgStrategy.hzDoList.clear();
	KgGlobalData::ms_hlkgStrategy.fzDoList.clear();
	
	QSettings setApp("../ini/xnbmsio.ini", QSettings::IniFormat);
	ms_hardwareOemID = setApp.value("XnBmsIO/OemID","1").toInt();
	ms_textCode = setApp.value("XnBmsIO/TextCode","1").toInt();
	printf("hardwareOemID:%d.\n", ms_hardwareOemID);
	QString strPort = setApp.value("XnBmsIO/PortName","ttySAC2").toString();//默认用ttySAC5接受空调数据 
	ms_IOConfigStr = strPort + QString(", DO:");
	ms_comDevName = QString("/dev/") + strPort;
	ms_hardwareOemID = setApp.value("XnBmsIO/OemID","1").toInt();
	ms_textCode = setApp.value("XnBmsIO/TextCode","1").toInt();
	ms_zz404D_addr = setApp.value("XnBmsIO/DevAddr","254").toInt();
	ms_hzEnabled = setApp.value("XnBmsIO/HzEnabled","1").toInt();
	ms_faultTkEnabled = setApp.value("XnBmsIO/FaultTkEnabled","0").toInt();
	ms_emgTkEnabled = setApp.value("XnBmsIO/EmgTkEnabled","1").toInt();
	ms_waterTkEnabled = setApp.value("XnBmsIO/WaterTkEnabled","0").toInt();
	ms_confSwitchEnabled = setApp.value("XnBmsIO/ConfSwitchEnabled","1").toInt();
	ms_execFltkFirst = setApp.value("XnBmsIO/ExecFltkFirst","1").toInt();
	ms_xfWarnFzEnabled = setApp.value("XnBmsIO/XfWarnFzEnabled","1").toInt();
	ms_xfAlarmFzEnabled = setApp.value("XnBmsIO/XfAlarmFzEnabled","1").toInt();
	ms_waterAlarmFzEnabled = setApp.value("XnBmsIO/WaterAlarmFzEnabled","1").toInt();
	ms_ctrlConfSwitchCount = setApp.value("XnBmsIO/CtrlConfSwitchCount","3").toInt();
	ms_devNo = setApp.value("XnBmsIO/DevNo","1").toInt();// added 2022-8-2
	ms_enabled485Alarm = setApp.value("XnBmsIO/Enabled485Alarm","1").toInt();
	ms_openFanTemp = setApp.value("XnBmsIO/OpenFanTemp","35").toInt();// added 2024-4-26
	ms_keepRegCtrlPos = setApp.value("XnBmsIO/KeepRegCtrlPos","0").toInt();

	KgGlobalData::ms_tkDelayTime = setApp.value("XnBmsIO/TkDelayTime","2").toFloat();
	if (KgGlobalData::ms_tkDelayTime < 0.2)
	{
		KgGlobalData::ms_tkDelayTime = 0.2;
	}
	if (KgGlobalData::ms_tkDelayTime > 2)
	{
		KgGlobalData::ms_tkDelayTime = 2;
	}
	
	KgGlobalData::ms_saveHlkgLog = setApp.value("XnBmsIO/SaveHlkgLogSec","0").toInt();
	//KgGlobalData::ms_reverseOrder = setApp.value("XnExtIO/ReverseOrder","0").toInt();
	KgGlobalData::ms_rwTimeoutSec = setApp.value("XnBmsIO/RwTimeout","1").toFloat();
	if(KgGlobalData::ms_rwTimeoutSec < 0.3)
	{
		KgGlobalData::ms_rwTimeoutSec = 0.3;
	}
	if(KgGlobalData::ms_rwTimeoutSec > 3)
	{
		KgGlobalData::ms_rwTimeoutSec = 3;
	}
		
	KgGlobalData::ms_devDoCount = setApp.value("XnBmsIO/DOCount","4").toInt();// ZZ-IO的输出干结点总个数
	if (KgGlobalData::ms_devDoCount > 16)
	{
		KgGlobalData::ms_devDoCount = 16;
	}
	if (KgGlobalData::ms_devDoCount < 4)
	{
		KgGlobalData::ms_devDoCount = 4;
	}
	
	KgGlobalData::ms_devDiCount = setApp.value("XnBmsIO/DICount","4").toInt();// ZZ-IO的输入干结点总个数
	if (KgGlobalData::ms_devDiCount > 16)
	{
		KgGlobalData::ms_devDiCount = 16;
	}
	if (KgGlobalData::ms_devDiCount < 4)
	{
		KgGlobalData::ms_devDiCount = 4;
	}

	KgGlobalData::ms_bcDiCount = setApp.value("XnBmsIO/BCDICount","0").toInt();
	if (KgGlobalData::ms_bcDiCount > 16)
	{
		KgGlobalData::ms_bcDiCount = 16;
	}
	KgGlobalData::ms_bcDoCount = setApp.value("XnBmsIO/BCDOCount","0").toInt();
	if (KgGlobalData::ms_bcDoCount > 16)
	{
		KgGlobalData::ms_bcDoCount = 16;
	}
	printf("ms_bcDiCount:%d, ms_bcDoCount:%d, ms_textCode:%d.\n", 
	    KgGlobalData::ms_bcDiCount, KgGlobalData::ms_bcDoCount, KgGlobalData::ms_textCode);
	
    ms_isOutputLog = setApp.value("XnBmsIO/IsOutputLog","1").toInt();
	ms_isSaveDetaiLog = setApp.value("XnBmsIO/SaveDetaiLogSec","0").toInt();
	//ms_hasUpsDryNode = setApp.value("DryCtrl/HasUpsDryNode","1").toInt();
	printf("devNo:%d, isOutputLog:%d, isSaveDetaiLog:%d.\n", ms_devNo, ms_isOutputLog, ms_isSaveDetaiLog);
	
	ms_diStartRegAddr = setApp.value("XnBmsIO/DiStartRegAddr","0").toInt();
	ms_doStartRegAddr = setApp.value("XnBmsIO/DoStartRegAddr","0").toInt();
	
    ms_closeFanDelayTime = setApp.value("XnBmsIO/CloseFanDelayTime","20").toInt();
	
    // 初始化两个IO模块的数据 // added 2022-8-2
	memset(&KgGlobalData::ms_dryData, 0, sizeof(DryData));
	memset(&KgGlobalData::ms_drySecData, 0, sizeof(DryData));
	KgGlobalData::ms_dryData.zz404D_addr    = ms_zz404D_addr;    // 设备地址
	KgGlobalData::ms_dryData.diStartRegAddr = ms_diStartRegAddr; // DI起始寄存器地址
	KgGlobalData::ms_dryData.doStartRegAddr = ms_doStartRegAddr; // DO起始寄存器地址
	KgGlobalData::ms_dryData.devDoCount     = ms_devDoCount;	 // ZZ-IO的输出干结点总个数
	KgGlobalData::ms_dryData.devDiCount     = ms_devDiCount;	 // ZZ-IO的输入干结点总个数
	KgGlobalData::ms_dryData.tkDelayTime    = ms_tkDelayTime;	 // 控制合闸分闸时，延时时间，单位：秒
	KgGlobalData::ms_dryData.rwTimeoutSec   = ms_rwTimeoutSec;   // IO模块读写超时时间，单位：秒 //added 2022-1-11

	KgGlobalData::ms_drySecData = KgGlobalData::ms_dryData;
	KgGlobalData::ms_drySecData.zz404D_addr = 2;// IODev2的地址固定为2
	// added end

	QString strDefaultPara = QString("3");
	int minCount = 2;
	KgGlobalData::ms_xfStrategy.confirmedCount = setApp.value("XnBmsIO/XfConfirmedCount", strDefaultPara).toInt();
	KgGlobalData::ms_waterStrategy.confirmedCount = setApp.value("XnBmsIO/WaterConfirmedCount", strDefaultPara).toInt();
	KgGlobalData::ms_tdStrategy.confirmedCount = setApp.value("XnBmsIO/TdConfirmedCount", strDefaultPara).toInt();
	KgGlobalData::ms_emgStopStrategy.confirmedCount = setApp.value("XnBmsIO/EmgConfirmedCount", strDefaultPara).toInt();
	KgGlobalData::ms_fuseStrategy.confirmedCount = setApp.value("XnBmsIO/FuseConfirmedCount", strDefaultPara).toInt();
	KgGlobalData::ms_xfMotionStrategy.confirmedCount = setApp.value("XnBmsIO/XfMotionConfirmedCount", strDefaultPara).toInt();
	KgGlobalData::ms_xfWarmStrategy.confirmedCount = setApp.value("XnBmsIO/XfWarmConfirmedCount", strDefaultPara).toInt();
	KgGlobalData::ms_combusGasStrategy.confirmedCount = setApp.value("XnBmsIO/CombusGasConfirmedCount", strDefaultPara).toInt();
	KgGlobalData::ms_upsAlmStrategy.confirmedCount = setApp.value("XnBmsIO/UpsAlmConfirmedCount", strDefaultPara).toInt();
	KgGlobalData::ms_doorAlmStrategy.confirmedCount = setApp.value("XnBmsIO/DoorAlmConfirmedCount", strDefaultPara).toInt();
    KgGlobalData::ms_doorAlmStrategySec.confirmedCount = setApp.value("XnBmsIO/DoorAlmSecConfirmedCount", strDefaultPara).toInt();
	KgGlobalData::ms_xfSprayStrategy.confirmedCount = setApp.value("XnBmsIO/XfSprayConfirmedCount", strDefaultPara).toInt();
    KgGlobalData::ms_xfFaultStrategy.confirmedCount = setApp.value("XnBmsIO/XfFaultConfirmedCount", strDefaultPara).toInt();
	KgGlobalData::ms_xfManuAutoStrategy.confirmedCount = setApp.value("XnBmsIO/XfManuAutoConfirmedCount", strDefaultPara).toInt();
    KgGlobalData::ms_elecPowerOffStrategy.confirmedCount = setApp.value("XnBmsIO/ElecPowerOffConfirmedCount", strDefaultPara).toInt();
	KgGlobalData::ms_mainSwitchStrategy.confirmedCount = setApp.value("XnBmsIO/MainSwitchConfirmedCount", strDefaultPara).toInt();
	KgGlobalData::ms_bmsLocalStrategy.confirmedCount = setApp.value("XnBmsIO/BmsLocalConfirmedCount", strDefaultPara).toInt();
	KgGlobalData::ms_bmsRemmoteStrategy.confirmedCount = setApp.value("XnBmsIO/BmsRemoteConfirmedCount", strDefaultPara).toInt();
	KgGlobalData::ms_acFaultStrategy.confirmedCount = setApp.value("XnBmsIO/AcFaultConfirmedCount", strDefaultPara).toInt();
    KgGlobalData::ms_lqFaultStrategy.confirmedCount = setApp.value("XnBmsIO/LqFaultConfirmedCount", strDefaultPara).toInt();

	KgGlobalData::ms_isolSwitchStrategy.confirmedCount = setApp.value("XnBmsIO/IsolSwitchConfirmedCount","10").toInt(); // 3S确认
	KgGlobalData::ms_connTimeoutCount = setApp.value("XnBmsIO/ConnTimeoutCount","10").toInt();

	if(KgGlobalData::ms_xfStrategy.confirmedCount < minCount)
	{
		KgGlobalData::ms_xfStrategy.confirmedCount = minCount;
	}
		
	if(KgGlobalData::ms_waterStrategy.confirmedCount < minCount)
	{
		KgGlobalData::ms_waterStrategy.confirmedCount = minCount;
	}

	if(KgGlobalData::ms_tdStrategy.confirmedCount < minCount)
	{
		KgGlobalData::ms_tdStrategy.confirmedCount = minCount;
	}
	
	if(KgGlobalData::ms_emgStopStrategy.confirmedCount < minCount)
	{
		KgGlobalData::ms_emgStopStrategy.confirmedCount = minCount;
	}

	if(KgGlobalData::ms_fuseStrategy.confirmedCount < minCount)
	{
		KgGlobalData::ms_fuseStrategy.confirmedCount = minCount;
	}

	if(KgGlobalData::ms_xfMotionStrategy.confirmedCount < minCount)
	{
		KgGlobalData::ms_xfMotionStrategy.confirmedCount = minCount;
	}

	if(KgGlobalData::ms_xfWarmStrategy.confirmedCount < minCount)
	{
		KgGlobalData::ms_xfWarmStrategy.confirmedCount = minCount;
	}

	if(KgGlobalData::ms_combusGasStrategy.confirmedCount < minCount)
	{
		KgGlobalData::ms_combusGasStrategy.confirmedCount = minCount;
	}

	if(KgGlobalData::ms_isolSwitchStrategy.confirmedCount < minCount)
	{
		KgGlobalData::ms_isolSwitchStrategy.confirmedCount = minCount;
	}

	if(KgGlobalData::ms_connTimeoutCount < minCount)
	{
		KgGlobalData::ms_connTimeoutCount = minCount;
	}
    KgGlobalData::ms_waterStrategySec.confirmedCount = KgGlobalData::ms_waterStrategy.confirmedCount;
	KgGlobalData::ms_tdStrategySec.confirmedCount = KgGlobalData::ms_tdStrategy.confirmedCount;
	KgGlobalData::ms_emgStopStrategySec.confirmedCount = KgGlobalData::ms_emgStopStrategy.confirmedCount;
	
    readFileDIDOConfig();
	
	writeKgLogfile(QString("ComDevName:%1, ZZIO404DAddr:%2, hzEnabled:%3")
		.arg(ms_comDevName).arg(ms_zz404D_addr).arg(ms_hzEnabled));
	writeKgLogfile(QString("DoCount:%1,diCount:%2,tkDelayTime:%3,rwTimeout:%4")
		.arg(KgGlobalData::ms_devDoCount).arg(KgGlobalData::ms_devDiCount).arg(KgGlobalData::ms_rwTimeoutSec).arg(KgGlobalData::ms_rwTimeoutSec));
    writeKgLogfile(QString("DiStartRegAddr:%1,doStartRegAddr:%2")
		.arg(KgGlobalData::ms_diStartRegAddr).arg(KgGlobalData::ms_doStartRegAddr));

	writeKgLogfile(QString("XfStrategy.confirmedCount:%1.").arg(KgGlobalData::ms_xfStrategy.confirmedCount));
	writeKgLogfile(QString("WaterStrategy.confirmedCount:%1.").arg(KgGlobalData::ms_waterStrategy.confirmedCount));
	writeKgLogfile(QString("TdStrategy.confirmedCount:%1.").arg(KgGlobalData::ms_tdStrategy.confirmedCount));
	writeKgLogfile(QString("EmgStopStrategy.confirmedCount:%1.").arg(KgGlobalData::ms_emgStopStrategy.confirmedCount));
	writeKgLogfile(QString("FuseStrategy.confirmedCount:%1.").arg(KgGlobalData::ms_fuseStrategy.confirmedCount));
	writeKgLogfile(QString("CombusGasStrategy.confirmedCount:%1.").arg(KgGlobalData::ms_combusGasStrategy.confirmedCount));
	writeKgLogfile(QString("IsolSwitchStrategy.confirmedCount:%1.").arg(KgGlobalData::ms_isolSwitchStrategy.confirmedCount));
	writeKgLogfile(QString("ConnTimeoutCount:%1, tkDelayTime:%2, RwTimeout:%3.").arg(KgGlobalData::ms_connTimeoutCount).arg(KgGlobalData::ms_tkDelayTime).arg(KgGlobalData::ms_rwTimeoutSec));

	writeKgLogfile(QString("XfStrategy.diIndex is %1(Number from 1).").arg(getDiName(KgGlobalData::ms_xfStrategy.diList)));
	writeKgLogfile(QString("TdStrategy.diIndex is %1(Number from 1).").arg(getDiName(KgGlobalData::ms_tdStrategy.diList)));
	writeKgLogfile(QString("EmgStopStrategy.diIndex is %1(Number from 1).").arg(getDiName(KgGlobalData::ms_emgStopStrategy.diList)));

	writeKgLogfile(QString("HlkgStrategy.hzDoIndex is %1(Number from 1).").arg(getDoName(KgGlobalData::ms_hlkgStrategy.hzDoList)));
	writeKgLogfile(QString("HlkgStrategy.fzDoIndex is %1(Number from 1).").arg(getDoName(KgGlobalData::ms_hlkgStrategy.fzDoList)));
	writeKgLogfile(QString("HlkgStrategy.diIndex is %1(Number from 1).").arg(getDiName(KgGlobalData::ms_hlkgStrategy.diCfgList)));
    writeKgLogfile(QString("step200"));
	
	// read db.ini
	QSettings setDB("../ini/db.ini", QSettings::IniFormat);
	m_strDriver = setDB.value("DB/Driver", m_strDriver).toString().trimmed().toUpper();
	m_strIP = setDB.value("DB/IP", m_strIP).toString();	
	m_usPort = (ushort)setDB.value("DB/Port", m_usPort).toUInt();	
	m_strDBName = setDB.value("DB/DBName", m_strDBName).toString();	 // SQLITE  DBName=../ini/xncfg.db
	m_strUserName = setDB.value("DB/UserName", m_strUserName).toString();	
	m_strPwd = setDB.value("DB/Pwd", m_strPwd).toString();

	// Read info from DB
	QString strDBType = "QMYSQL";
	bool bDBOpen = false;
	int iRetVal = -999;
	int iBankNum = 0;
	m_strDriver = m_strDriver.trimmed().toUpper();

	if ("MYSQL" == m_strDriver)
	{
		strDBType = "QMYSQL";
	}
	else if ("ORACLE" == m_strDriver)
	{
		strDBType = "QOCI";  
	}
	else if ("SQLITE" == m_strDriver)
	{
		strDBType = "QSQLITE";  
	}

	g_db = QSqlDatabase::addDatabase(strDBType);
	g_db.setHostName(m_strIP);
	g_db.setPort(m_usPort);
	g_db.setDatabaseName(m_strDBName);
	g_db.setUserName(m_strUserName);
	g_db.setPassword(m_strPwd);  

	if(g_db.open())
	{		
		if ("QSQLITE" == strDBType)// 如是SQLITE数据库,需要判断表是否存在,来确定库是否打开 以工程信息表来判断 数据打开是否成功
		{
			QStringList strTableList = g_db.tables(QSql::Tables);

			if(!strTableList.contains("tblBattery", Qt::CaseInsensitive))//不存在该表
			{			
				bDBOpen = false;
			}
			else
			{
				bDBOpen = true;
			}
		}
		else
		{
			bDBOpen = true;
		}
	}
	else
	{	
		bDBOpen = false;
	}
	
	writeKgLogfile(QString("Open db result:%1").arg(bDBOpen));
	return 1;
}

int KgGlobalData::InitRtdb()//初始化Rtdb
{	
   // Read info from DB
	writeKgLogfile("InitRtdb");
	QString strHint;;
	int iRetVal = -999;
	int iBankNum = 8;//////

	KgGlobalData::ms_installBankNum = 0;
	KgGlobalData::ms_pIOModule = new CIOModule;
	memset(KgGlobalData::ms_pIOModule, 0, sizeof(CIOModule));
	
	ms_pRTDB = new CRTDB(1, 1, MAX_BANK_NUM, NULL);
    //writeKgLogfile("try attach RTDB");
	if(!ms_pRTDB || ms_pRTDB->initRTDB(true) < 0)//false表示关联到共享内存中
	{
		iRetVal = -1;
		writeKgLogfile("Attach RTDB FAILED.");
		return iRetVal;
	}		
	else
	{
	    writeKgLogfile("Attach RTDB succeed.");
		iRetVal= 0;
		KgGlobalData::ms_pStack = ms_pRTDB->getStack(0);
		getInstallInfo();
		strHint = QString("UsInstallBankNum:%1, usBankNumInStack:%2.")
				.arg(KgGlobalData::ms_installBankNum).arg(KgGlobalData::ms_bankNumInStack);
	    writeKgLogfile(strHint);

		if(KgGlobalData::ms_pStack)
		{  
#ifdef BMS_MAIN_VER36
			CBattStack* pStack = KgGlobalData::ms_pStack;
			if (BAMS_VERSION_MAJOR != pStack->uaRtdbVersMajor || 
				BAMS_VERSION_MINOR != pStack->uaRtdbVersMinor || 
				BAMS_VERSION_REVISION != pStack->uaRtdbVersRevision) 
			{
				pStack->usVersIncomp = 1;
				iRetVal = -4;
			}
			else
			{
				pStack->uaExIOVers = APP_VERSION_MAJOR;  // Version    
				pStack->uaExIOVers = pStack->uaExIOVers << 4; 
				pStack->uaExIOVers |= APP_VERSION_MIDDLE;
			}
#endif
		}
	}
	
	/*
	BattStackPara stackPara;
	QString devInstCode;
	devInstCode = "KG_BAMS1";

	stackPara.devType = "BAMS";
	
	stackPara.devInstCode = devInstCode;
	stackPara.modbusAddr = 1;//堆地址
	stackPara.groupCount = KgGlobalData::ms_installBankNum;
	if(stackPara.groupCount > MAX_BANK_NUM)
	{
		stackPara.groupCount = MAX_BANK_NUM;
	}
	
	KgGlobalData::ms_batStackList.append(stackPara);//初始化堆参数

	int col = 1;
	for(int k = 0; k < stackPara.groupCount; ++k)
	{
	    CBattBank *pBank = ms_pRTDB->getBank(k);
		BattGroupPara batPara;
		batPara.devType = "BAMS";
		batPara.devInstCode = devInstCode;
		batPara.modbusAddr = k+2;//组地址从2开始编号
		if (pBank)
		{
		   	batPara.batCnt = pBank->usCellNumInBank;// 电池节数
		    batPara.tempCnt = pBank->usTempNumInBank;// 温度个数
		}
		else//出错，初始化一个值
		{
		   	batPara.batCnt  = 100;//
		    batPara.tempCnt = 100;//
		}
		strHint = QString("Bank%1 usCellNum:%2, usTempNum:%3").arg(k+1).arg(batPara.batCnt).arg(batPara.tempCnt);
		writeKgLogfile(strHint);

		KgGlobalData::ms_batGroupList.append(batPara);//初始化组参数
	}
	*/

	return iRetVal;
}

int g_iLogCount = 0;
//输出日志
void writeKgLogfile(QString strInfo, bool bSaveToFile)
{
	int year = 0;
	int month = 0;
	int day = 0;
    int h = 0;
    int m = 0;
    int s = 0;
    int msec = 0;
    getCurrentTime(year, month, day, h, m, s, msec);
    QChar fillChar = '0';
    QString strLog = QString("%1-%2-%3 %4:%5:%6.%7 %8")
		.arg(year,4,10,fillChar).arg(month,2,10,fillChar).arg(day,2,10,fillChar)
		.arg(h,2,10,fillChar).arg(m,2,10,fillChar).arg(s,2,10,fillChar).arg(msec,3,10,fillChar).arg(strInfo);

	if(g_iLogCount < 30000)
	{
		g_iLogCount += 1;
		qDebug() << strLog;
	}
	
	//return;///////////////////////////////////////////////

	if (1 != KgGlobalData::ms_isOutputLog)//不输出日志
	{
		return;
	}
	
	if (!bSaveToFile)
    {
        return;
    }

	int fileSize = KgGlobalData::ms_logFile.fileSize();
	if (fileSize >= 1024*1024*3)//日志文件过大，不再输出
	{
		return;
	   // printf("log size:%d, too large to delete\n", fileSize);
	   
	   // KgGlobalData::ms_logFile.close();
	   // QString   logFileName = QString("../log/modbsrv.log");
	   // QFile file(logFileName);
	   // file.remove();
	   
	   // KgGlobalData::ms_logFile.createlogfile(logFileName);	
	}
	
	KgGlobalData::ms_logFile.writelogfile(strInfo);
}


int g_iBcLogCount = 0;
//输出日志
void writeKgBcLogfile(QString strInfo, bool bSaveToFile)
{
	int year = 0;
	int month = 0;
	int day = 0;
    int h = 0;
    int m = 0;
    int s = 0;
    int msec = 0;
    getCurrentTime(year, month, day, h, m, s, msec);
    QChar fillChar = '0';
    QString strLog = QString("%1-%2-%3 %4:%5:%6.%7 %8")
		.arg(year,4,10,fillChar).arg(month,2,10,fillChar).arg(day,2,10,fillChar)
		.arg(h,2,10,fillChar).arg(m,2,10,fillChar).arg(s,2,10,fillChar).arg(msec,3,10,fillChar).arg(strInfo);

	if(g_iBcLogCount < 30000)
	{
		g_iBcLogCount += 1;
		qDebug() << strLog;
	}
	
	//return;///////////////////////////////////////////////

	if (1 != KgGlobalData::ms_isOutputLog)//不输出日志
	{
		return;
	}
	
	if (!bSaveToFile)
    {
        return;
    }

	int fileSize = KgGlobalData::ms_bclogFile.fileSize();
	if (fileSize >= 1024*1024*3)//日志文件过大，不再输出
	{
		return;
	   // printf("log size:%d, too large to delete\n", fileSize);
	   
	   // KgGlobalData::ms_logFile.close();
	   // QString   logFileName = QString("../log/modbsrv.log");
	   // QFile file(logFileName);
	   // file.remove();
	   
	   // KgGlobalData::ms_logFile.createlogfile(logFileName);	
	}	
		
	KgGlobalData::ms_bclogFile.writelogfile(strInfo);
}

//********************************************************************
// FUCTION: Modbus_CRC16 —— MODBUS RTU CRC16校验生成函数
// VERSION: 1	(2010-9-27 14:34:01)
// INPUT:	dat_buf 待校验数值缓存区
// 			dat_len 待校验数值缓存区的长度
// OUTPUT:	CRC16校验值
// EXAMPLE:
// 输入数据 dat_buf指向的数组为： 0x33, 0x78, 0x98, 0x60, 校验长度为4
// 则输出为：高字节0xE4 低字节0x91
// NOTE：	参考技术标准文件《高特MODBUS通讯规约3.0标准版》		
//********************************************************************
 UINT16 Modbus_CRC16(UINT8 *dat_buf,UINT16 dat_len)  //ScuBch
{
	/* CRC 高位字节值表 */
	const UINT8 AUCHCRCHI[256]=
	{
		0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
		0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
		0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
		0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
		0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
		0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
		0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
		0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
		0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
		0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
		0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
		0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
		0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
		0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
		0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
		0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
		0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
		0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
		0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
		0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
		0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
		0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
		0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
		0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
		0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
		0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
		0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
		0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
		0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40,
		0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
		0x00,0x0C1,0x81,0x40,0x01,0x0C0,0x80,0x41,
		0x01,0x0C0,0x80,0x41,0x00,0x0C1,0x81,0x40
	};
	
	/* CRC 低位字节值表 */
	const UINT8 AUCHCRCLO[256]=
	{
		0,0xC0,0xC1,0x01,0xC3,0x03,0x02,0xC2,
		0xC6,0x06,0x07,0xC7,0x05,0xC5,0xC4,0x04,
		0xCC,0x0C,0x0D,0xCD,0x0F,0xCF,0xCE,0x0E,
		0x0A,0xCA,0xCB,0x0B,0xC9,0x09,0x08,0xC8,
		0xD8,0x18,0x19,0xD9,0x1B,0xDB,0xDA,0x1A,
		0x1E,0xDE,0xDF,0x1F,0xDD,0x1D,0x1C,0xDC,
		0x14,0xD4,0xD5,0x15,0xD7,0x17,0x16,0xD6,
		0xD2,0x12,0x13,0xD3,0x11,0xD1,0xD0,0x10,
		0xF0,0x30,0x31,0xF1,0x33,0xF3,0xF2,0x32,
		0x36,0xF6,0xF7,0x37,0xF5,0x35,0x34,0xF4,
		0x3C,0xFC,0xFD,0x3D,0xFF,0x3F,0x3E,0xFE,
		0xFA,0x3A,0x3B,0xFB,0x39,0xF9,0xF8,0x38,
		0x28,0xE8,0xE9,0x29,0xEB,0x2B,0x2A,0xEA,
		0xEE,0x2E,0x2F,0xEF,0x2D,0xED,0xEC,0x2C,
		0xE4,0x24,0x25,0xE5,0x27,0xE7,0xE6,0x26,
		0x22,0xE2,0xE3,0x23,0xE1,0x21,0x20,0xE0,
		0xA0,0x60,0x61,0xA1,0x63,0xA3,0xA2,0x62,
		0x66,0xA6,0xA7,0x67,0xA5,0x65,0x64,0xA4,
		0x6C,0xAC,0xAD,0x6D,0xAF,0x6F,0x6E,0xAE,
		0xAA,0x6A,0x6B,0xAB,0x69,0xA9,0xA8,0x68,
		0x78,0xB8,0xB9,0x79,0xBB,0x7B,0x7A,0xBA,
		0xBE,0x7E,0x7F,0xBF,0x7D,0xBD,0xBC,0x7C,
		0xB4,0x74,0x75,0xB5,0x77,0xB7,0xB6,0x76,
		0x72,0xB2,0xB3,0x73,0xB1,0x71,0x70,0xB0,
		0x50,0x90,0x91,0x51,0x93,0x53,0x52,0x92,
		0x96,0x56,0x57,0x97,0x55,0x95,0x94,0x54,
		0x9c,0x5c,0x5d,0x9d,0x5f,0x9f,0x9e,0x5e,
		0x5a,0x9a,0x9b,0x5b,0x99,0x59,0x58,0x98,
		0x88,0x48,0x49,0x89,0x4b,0x8b,0x8a,0x4a,
		0x4e,0x8e,0x8f,0x4f,0x8d,0x4d,0x4c,0x8c,
		0x44,0x84,0x85,0x45,0x87,0x47,0x46,0x86,
		0x82,0x42,0x43,0x83,0x41,0x81,0x80,0x40 
	};
	
	UINT8 j,CH,CL;
	UINT16 i;
	CH = 0XFF;
	CL = 0XFF;
	for(i = 0; i < dat_len; i++)
	{
		j = dat_buf[i];
		j = CH ^ j;
		CH = CL ^ AUCHCRCHI[j];
		CL = AUCHCRCLO[j];
	}
	
	return(CH * 0x100 + CL);
}

void getCurrentTime(int &year, int &month, int &day, int &h, int &m, int &s, int &msec)
{
   	QDateTime now = QDateTime::currentDateTime();
	QDate dt = now.date();
	QTime time = now.time();
	
	year = dt.year();
	month = dt.month();
	day = dt.day();
	
	h = time.hour();
	m = time.minute();
	s = time.second();
	msec = time.msec();
}

//获取需要断开接触器的电组池总组数 2019-10-12
int NeedBreakJCQCount()
{
	CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
	if (!pStack)
	{
	    return  0;
	}
	int count = 0;
	//quint16 usStackCfgInfo = pStack->usStackCfgInfo;
  
	for(int grp = 0; grp < KgGlobalData::ms_installBankNum; ++grp)
	{
	    CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(grp);
		if (!pBank)
		{
		   continue;
		}

		if (isBankInStack(grp))
		{
			//printf("===========bank%d， usNeedCloseJCQ:%d\n", grp+1, pBank->usNeedCloseJCQ);
			// modified 2021-4-17
			// 通用版 quint16 usNeedCloseJCQ;     // 1 - 需要闭合  0 - 不需要闭合 
			// 南都版 quint16 usNeedCloseJCQ;     // 0 - 保持(不需要闭合)  1 - 需要闭合   2 - 切出   11 - 强制闭合  12 - 强制切出
#ifdef MASTER_VER
			if (0 == pBank->usNeedCloseJCQ)  // 1 - 需要闭合  0 - 不需要闭合
		    {
		        count += 1;
		    }
#else
			if (12 == pBank->usNeedCloseJCQ)  // 12 - 强制切出
		    {
		        count += 1;
		    }
#endif
		}
    }
	
	return count;
}

//获取需要闭合接触器的电组池总组数 2019-11-28
int NeedCloseJCQCount()
{
	CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
	if (!pStack)
	{
	    return  0;
	}
	int count = 0;
	//quint16 usStackCfgInfo = pStack->usStackCfgInfo;
  
	for(int grp = 0; grp < KgGlobalData::ms_installBankNum; ++grp)
	{
	    CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(grp);
		if (!pBank)
		{
		   continue;
		}
		
		if (isBankInStack(grp))
		{	// modified 2021-4-17
		    // 通用版 quint16 usNeedCloseJCQ;     // 1 - 需要闭合  0 - 不需要闭合 
			// 南都版 quint16 usNeedCloseJCQ;     // 0 - 保持(不需要闭合)  1 - 需要闭合   2 - 切出   11 - 强制闭合  12 - 强制切出
#ifdef MASTER_VER
			if (1== pBank->usNeedCloseJCQ)  // 1 - 需要闭合  0 - 不需要闭合
		    {
		        count += 1;
		    }
#else
			if (11 == pBank->usNeedCloseJCQ)  //  11 - 强制闭合
		    {
		        count += 1;
		    }
#endif
		}
    }
	
	return count;
}

//获取正接触器闭合的电池组数?2020-5-5
int GetClosedJCQCount()
{
 	CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
	if (!pStack)
	{
	    return  0;
	}
	int count = 0;
	//quint16 usStackCfgInfo = pStack->usStackCfgInfo;
  
	for(int grp = 0; grp < KgGlobalData::ms_installBankNum; ++grp)
	{
	    CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(grp);
		if (!pBank)
		{
		   continue;
		}
		
		if (isBankInStack(grp))
		{
			if (1 == pBank->usDI1) // 正接触器闭合
		    {
		        count += 1;
		    }
		}
    }
	
	return count;
}

int judgeJcqCount = 0;
//获取正接触器断开的电池组数 2020-5-19
int GetOpenedJCQCount()
{
	CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
	if (!pStack)
	{
	    return  0;
	}
	else
	{ 
#ifdef MASTER_VER
		writeKgLogfile(QString("usConfSwitchStrategy:%1, usConfSwitchState:%2")
		.arg(pStack->usConfSwitchStrategy).arg(pStack->usConfSwitchState));
#endif
	}
	
	int count = 0;
	//quint16 usStackCfgInfo = pStack->usStackCfgInfo;

	if(++judgeJcqCount >= 6)
	{
		judgeJcqCount = 0;
	}
	
	for(int grp = 0; grp < KgGlobalData::ms_installBankNum; ++grp)
	{
	    CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(grp);
		if (!pBank)
		{
		   continue;
		}
		
		if (isBankInStack(grp))
		{
			if(0 == judgeJcqCount)
			{
				writeKgLogfile(QString("***grp%1 DI1-2 of BCMU:%2,%3").arg(grp+1).arg(pBank->usDI1).arg(pBank->usDI2));
			}
		    if (0== pBank->usDI1) //正接触器断开
		    {
		        count += 1;
		    }
		}
		else
		{
			if(0 == judgeJcqCount)
			{
				writeKgLogfile(QString("~~~grp%1 DI1-2 of BCMU:%2,%3").arg(grp+1).arg(pBank->usDI1).arg(pBank->usDI2));
			}
		} 
    }
	
	return count;
}

//BankAddr=999 // 999 表示烟感消防接在 BAMS 的 DI3上
//通知消防告警到BAMS，BA运行状态由正常转为跳机，各组状态切换到开路
void SetBamsFireAlarm(char fireAlarm)
{
    CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
    writeKgLogfile(QString("usFireBankAddr:%1.").arg(pStack->usFireBankAddr));
   
	if (pStack)
	{
		if (999 == pStack->usFireBankAddr)//  // 电池组地址 0 - 未配置 100 - 每组BC单独接   999 - 接BA  消防接DI3
		{
			//BA收到会报：消防报警(接BAMS)   (组号为1)
			if (1 == pStack->usFireAlarmValue)
			{
				pStack->usDI3 = fireAlarm; 
				writeKgLogfile(QString("step1=======FireAlarm pStack->usDI3:%1.").arg(pStack->usDI3));
			}
			else
			{
				pStack->usDI3 = (!fireAlarm); 
				writeKgLogfile(QString("step2=======FireAlarm pStack->usDI3:%1.").arg(pStack->usDI3));
			}
		}

// added 2021-12-10
#ifdef ND_VER_PROGRAM 		// 南都版本
		if (fireAlarm) // 发生消防报警
		{
			pStack->usStackTotAlarm = pStack->usStackTotAlarm | (1 << 8);
		}
		else      // 正常
		{
			pStack->usStackTotAlarm = pStack->usStackTotAlarm & (~(1 << 8));
		}
#endif

#ifdef ND_LD_PRJ
		if(KgGlobalData::ms_diAlarmVals.size() >= 4)
		{
			int alarmVal = KgGlobalData::ms_diAlarmVals[3];
			if(alarmVal) // DI4配置为常开干结点
			{
				if((8  & g_DIState) == 8) // ZZ-IO404D-DI4-消防灭火 BA-DI2
				{
					if(fireAlarm) // 确认消防告警时才置位
					   pStack->usDI2 = 1;
					else
					   pStack->usDI2 = 0;
				}
				else
				{
					pStack->usDI2 = 0;
				}
			}
			else // DI4配置为常闭干结点 (现场配置为常闭，执行这里)
			{
				if((8  & g_DIState) == 8) // ZZ-IO404D-DI4-消防灭火 BA-DI2
				{
					pStack->usDI2 = 0;
				}
				else
				{
				    if(fireAlarm) // 确认消防告警时才置位
					  pStack->usDI2 = 1;
					else
					  pStack->usDI2 = 0;
				}
			}
		}
#endif
	}

	//BA收到会报：消防报警(接BAMS)   (组号为2,3,4,5...)
	/*for(int k = 0; k < KgGlobalData::ms_installBankNum; ++k)
	{
	    CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(k);
		if (pBank)
		{
            pBank->aFireAlarm  = fireAlarm;
		}
    }*/
}

void SetBamsWaterAlarm(char waterAlarm)
{
    CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
	writeKgLogfile(QString("usWaterBankAddr:%1.").arg(pStack->usWaterBankAddr));
#ifdef ND_VER_PROGRAM 		// 南都版本, 水浸由消防改变而来 2021-11-30  改xnview_zh.qm
	
	return;
    writeKgLogfile(QString("=============================================== ND_VER_PROGRAM"));
	
#endif
	if (pStack)
	{
		if (999 == pStack->usWaterBankAddr)// 电池组地址 0 - 未配置 999 - 接BA  水浸接DI4
		{
			//BA收到会报：水浸报警(接BAMS)   (组号为1)
			if (1 == pStack->usWaterAlarmValue)
			{
				pStack->usDI4 = waterAlarm; 
				writeKgLogfile(QString("step3=======WaterAlarm pStack->usDI4:%1.").arg(pStack->usDI4));
			}
			else
			{
				pStack->usDI4 = (!waterAlarm); 
				writeKgLogfile(QString("step4=======WaterAlarm pStack->usDI4:%1.").arg(pStack->usDI4));
			}
		}
	}
}

void  SetFuseAlarm(char alarm) // added 2022-11-15
{
	CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
	if (pStack)
	{
		
	    // quint16 usFuseStrategy;   // 熔丝策略   0 - 无熔丝 [1 - 每组BC(DI2)反馈 2 - 每组BC(DI3)反馈  
	    // 3 - 每组BC(DI4)反馈 常开] [11 - 每组BC(DI2)反馈 12 - 每组BC(DI3)反馈  13 - 每组BC(DI4)反馈 常闭] 999 - 接BA DI2(常闭)  
		if (999 == pStack->usFuseStrategy)// 999 - 接BA DI2(常闭)  
		{
			//pStack->usDI2 = alarm; // modified 2023-2-10
			if(alarm)
				pStack->usDI2 = 0; 
			else
				pStack->usDI2 = 1; 
			writeKgLogfile(QString("step5=======usFuseAlarm pStack->usDI2:%1.").arg(pStack->usDI2));
		}
		else
		{
			//if(alarm)
			//  writeKgLogfile(QString("SetFuseAlarm=======pStack->usFuseStrategy:%1.").arg(pStack->usFuseStrategy));
			writeKgLogfile(QString("step6=======usFuseAlarm pStack->usDI2:%1.").arg(pStack->usDI2));

		}
	}
}

// 设置隔离开关状态
void SetIsolSwitchAggrState (char state)
{
	CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
	if (pStack)
	{
		if (200 == pStack->usIsolSwitchStrategy) // 200 - 3rd进程设定
		{
			pStack->usIsolSwitchAggrState = state; // 隔离开关汇总状态 0 - 断开  1 - 全部闭合
		}
	}
}

// 通知BA紧急停机
void SetEmergeStopAlarm(char alarm)
{
    CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
	if (pStack)
	{
#ifdef	ND_VER_PROGRAM  // added 2021-3-13
		if (999 == pStack->usWaterBankAddr)// 电池组地址 0 - 未配置 999 - 接BA  水浸接DI4     紧急停机
		{
			if (1 == pStack->usWaterAlarmValue) // 常开结点
			{
				pStack->usDI4 = alarm; 
				writeKgLogfile(QString("step5 WaterAlarm pStack->usDI4=%1").arg(pStack->usDI4));
			}
			else                               // 常闭结点
			{
				pStack->usDI4 = (!alarm); 
				writeKgLogfile(QString("step6 WaterAlarm pStack->usDI4=%1").arg(pStack->usDI4));
			}
		}
#else
		if (200 == pStack->usEmerStopStrategy)
		{
		   // quint16 usEmerStopState;  // 紧急停机状态   0 - 默认  1 - 告警  2 - 正常
			if (alarm) // 发生急停
			{
				pStack->usEmerStopState = 1;
				writeKgLogfile(QString("step3 EmerStopState pStack->usEmerStopState=%1").arg(pStack->usEmerStopState));
			}
			else       // 正常
			{
				pStack->usEmerStopState = 2;
				writeKgLogfile(QString("step4 EmerStopState pStack->usEmerStopState=%1").arg(pStack->usEmerStopState));
			}
		}
#endif

// added 2021-1-5
#ifdef ND_VER_PROGRAM 	// 南都版本
		if (alarm) // 发生急停
		{
			pStack->usStackTotAlarm = pStack->usStackTotAlarm | (1 << 6);
		}
		else      // 正常
		{
			pStack->usStackTotAlarm = pStack->usStackTotAlarm & (~(1 << 6));
		}
#endif
	}
}

// 力神珠海项目特殊处理部分
void lszhUpdateRtdb(CBattStack *pStack, quint16 replyState[6])
{
	int pos = 6;

	//step1: 更新断路器状态，modbusTCP读取会用到 modbus地址:27~30
	pStack->usStackTemp[pos++]= replyState[0]; // 断路器1状态  27 
	pStack->usStackTemp[pos++]= replyState[1]; // 断路器2状态  28
	pStack->usStackTemp[pos++]= replyState[2];
	pStack->usStackTemp[pos++]= replyState[3];

	if (KgGlobalData::ms_dryData.failedCount >= KgGlobalData::ms_connTimeoutCount) // 通迅故障
	{
		 pStack->usStackTemp[pos++] = 1;
	}
	else
	{
		 pStack->usStackTemp[pos++] = 0;
	}

	//step2: 更新SVG用redis测点 ZH_KG_BAMS1_1.DI1   //电池堆1断路器状态   1:闭合  0:断开 
	if(0 == replyState[0] + replyState[1] + replyState[2] + replyState[3]) // 4个断路器都没有脱扣
	{
		pStack->usDI1 = 1;
	}
	else
	{
		pStack->usDI1 = 0;
	}

	//step3: 更新SVG用redis测点 ZH_KG_BAMS1_1.fStackTemp1   //电池堆1功率 单位:kW   
	float fStackPower = pStack->fStackVol * pStack->fStackCur / 1000.0;
	pStack->fStackTemp[0] = fStackPower;
}

/*
	pStack->usStackTemp[23]：Bit0:消防告警  Bit1: 消防启动   Bit2:消防故障  Bit3:消防手自动
    pStack->usStackTemp[24]: Bit0:UPS告警   Bit1:门禁告警    Bit2:水浸告警  Bit3:燃气告警
                             Bit4: 市电断电 Bit5:防雷告警    Bit6:熔断器告警Bit7:急停
*/

//更新DI1-4数据到BA的通用保持寄存器50-53中 2020-1-15
int g_count2 = 0;
void  updateDryDataToRtdb(DryCtrlThread *pThread)
{
	CBAComReg *pComReg = KgGlobalData::ms_pRTDB->getBAComReg(0);
	CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
	//return;// *********************************************
	//printf("**************** return 2\n");
	
	//int pos = 0;
	if (!pComReg || !pStack)
	{ 
	   printf("pComReg==========NULL\n");
	   return;
	}

    int connError = 0;
	if(KgGlobalData::ms_dryData.failedCount > 5)
	{
		connError = 1;
	}

	quint16 emergStopAlarm = 0;     // added 2022-1-12
	if(pThread->hasEmertStopAlarm())//  // 紧急停机状态             0 - 默认  1 - 告警  2 - 正常
	{
		emergStopAlarm = 1;
	}

	pStack->usStackTemp[25]	= KgGlobalData::ms_dryData.DIVal;
	pStack->usStackTemp[26]	= KgGlobalData::ms_dryData.IOCtrl;
	
	quint16 xfAlarmWord = 0;
	if(pThread->m_fireAlarm > 0)// 消防告警
	    xfAlarmWord |= 1;
	if(pThread->m_fireSprayAlarm > 0)// 消防启动
	    xfAlarmWord |= 2;
	if(pThread->m_fireFaultAlarm > 0)// 消防故障
	    xfAlarmWord |= 4;
	if(pThread->m_fireManuMode > 0) // 消防手自动
	    xfAlarmWord |= 8;
	pStack->usStackTemp[28]	= xfAlarmWord;

	quint16 otherWord = 0;
	if(pThread->m_upsAlarm > 0)  // UPS告警 DI4
	    otherWord |= 1;
	if(pThread->m_doorAlarm > 0) // 门禁告警 DI5
        otherWord |= 2;
	if(pThread->m_waterAlarm > 0)// 水浸告警
        otherWord |= 4;
	if(pThread->m_combusGasAlarm > 0)// 燃气告警
        otherWord |= 8;
	if(pThread->m_elecPowerOffAlarm > 0)// 市电断电
	    otherWord |= 0x10;
	if(pThread->m_thunderAlarm > 0)    // 防雷告警
	    otherWord |= 0x20;
	if(pThread->m_fuseAlarm > 0)       // 熔断器告警
	    otherWord |= 0x40;
	if(pThread->m_emergStopAlarm > 0)  // 急停
	    otherWord |= 0x80;
	if(pThread->m_mainSwitchClosed > 0)// 主断路器状态
		otherWord |= 0x100;
	pStack->usStackTemp[29]	= otherWord;

	int pos = 10;
	//pStack->usStackHoldTemp[pos++] = xfAlarmWord;  
	//pStack->usStackHoldTemp[pos++] = otherWord; 
	if(g_count2 < 50)
	{
		g_count2 += 1;
		for(int k = 0; k < 1; ++k)
		{
			printf("step1*****************usStackTemp[0--5]:%d-%d-%d-%d-%d-%d\n", pStack->usStackTemp[0], pStack->usStackTemp[1],
			    pStack->usStackTemp[2],pStack->usStackTemp[3],pStack->usStackTemp[4],pStack->usStackTemp[5]);
		}
		printf("step2****************usStackTemp[25][26][28][29]:%d, %d, %d, %d\n",
			  pStack->usStackTemp[25], pStack->usStackTemp[26], pStack->usStackTemp[28], pStack->usStackTemp[29]);
	}
	return; // **************************************************************


    connError = 0;
	if(KgGlobalData::ms_dryData.failedCount > 5)
	{
		connError = 1;
	}

	emergStopAlarm = 0;     // added 2022-1-12
	if(pThread->hasEmertStopAlarm())//  // 紧急停机状态             0 - 默认  1 - 告警  2 - 正常
	{
		emergStopAlarm = 1;
	}
	
	// added 2021-11-03 
	
	pComReg->usComInputRegVal[pos++] = KgGlobalData::ms_dryData.DIVal;   // DI当前值
	pComReg->usComInputRegVal[pos++] = connError;                        // IO模块通信故障   0-正常 1-通信故障
	pComReg->usComInputRegVal[pos++] = pThread->getConfSwitchState();    // 汇流开关反馈     0-断开 1-闭合
	pComReg->usComInputRegVal[pos++] = pThread->getIsolSwitchAggrState();// 隔离开关反馈     0-断开 1-闭合
	pComReg->usComInputRegVal[pos++] = pThread->m_fireAlarm;             // 消防告警         0-正常 1-告警
	pComReg->usComInputRegVal[pos++] = pThread->m_waterAlarm;            // 水浸告警         0-正常 1-告警
	pComReg->usComInputRegVal[pos++] = pThread->m_thunderAlarm;          // 雷击告警         0-正常 1-告警
	pComReg->usComInputRegVal[pos++] = emergStopAlarm;// pThread->m_emergStopAlarm; // 系统急停         0-正常 1-急停
	pComReg->usComInputRegVal[pos++] = pThread->m_combusGasAlarm;        // 可燃气体告警

#ifdef ND_VER_PROGRAM // added 2022-10-12
	if (pThread->getConfSwitchState() > 0) // 汇流开关闭合
	{
		pStack->usStackTotAlarm = pStack->usStackTotAlarm | (1 << 9);
	}
	else      // 断开
	{
		pStack->usStackTotAlarm = pStack->usStackTotAlarm & (~(1 << 9));
	}
#endif

#ifdef HJ_5MWH
if(pThread->m_fireAlarm > 0)// 消防告警
	    pStack->usStackTemp[23] = 1;
	else
	    pStack->usStackTemp[23] = 0;
#endif

#ifdef ND_HNXJ // added 2022-10-12
//if(KgGlobalData::ms_hasUpsDryNode > 0)
//if(pThread->m_fireAlarm > 0)// 消防告警
	if(pThread->m_fuseAlarm > 0)// 消防告警 DI2
	    pStack->usStackTemp[23] = 1;
	else
	    pStack->usStackTemp[23] = 0;
	
	if(pThread->m_upsAlarm > 0)// UPS告警 DI4
	    pStack->usStackTemp[24]	= 1;
	else
		pStack->usStackTemp[24]	= 0;
	
    if(pThread->m_doorAlarm > 0)// 门禁告警 DI5
        pStack->usStackTemp[25] = 1;
	else
		pStack->usStackTemp[25]	= 0;

/*if(1 == KgGlobalData::ms_devNo)
{
	//if(pThread->m_fireAlarm > 0)// 消防告警
	if((KgGlobalData::ms_dryData.DIVal & 2) > 0)// 消防告警 DI2
	    pStack->usStackTemp[23] = 1;
	else
	    pStack->usStackTemp[23] = 0;
	
	if((KgGlobalData::ms_dryData.DIVal & 8) > 0)// UPS告警 DI4
	    pStack->usStackTemp[24]	= 1;
	else
		pStack->usStackTemp[24]	= 0;
	
    if((KgGlobalData::ms_dryData.DIVal & 16) > 0)// 门禁告警 DI5
        pStack->usStackTemp[25] = 1;
	else
		pStack->usStackTemp[25]	= 0;
}
else
{
	if((KgGlobalData::ms_dryData.DIVal & 2) > 0 || 
		(KgGlobalData::ms_dryData.DIVal & 16) > 0 ||
		(KgGlobalData::ms_dryData.DIVal & 32) > 0)// 消防告警 DI2 DI5 DI6
	    pStack->usStackTemp[23] = 1;
	else
	    pStack->usStackTemp[23] = 0;
	
		pStack->usStackTemp[24]	= 0;// UPS告警 empty
		
		pStack->usStackTemp[25]	= 0;// 门禁告警 empty
}*/
#endif

    if((KgGlobalData::ms_dryData.DIVal & 1) > 0)// 消防火警 DI1
	    pStack->usStackTemp[2] = 1;
	else
	    pStack->usStackTemp[2] = 0;
	
	if((KgGlobalData::ms_dryData.DIVal & 2) > 0)// 消防喷放 DI2
	    pStack->usStackTemp[3] = 1;
	else
		pStack->usStackTemp[3] = 0;
	
    if((KgGlobalData::ms_dryData.DIVal & 4) > 0)// 消防故障 DI3
        pStack->usStackTemp[4] = 1;
	else
		pStack->usStackTemp[4] = 0;

	if((KgGlobalData::ms_dryData.DIVal & 0x10) > 0)// 门禁 DI5
        pStack->usStackTemp[5] = 1;
	else
		pStack->usStackTemp[5] = 0;
 
    //if(KgGlobalData::ms_devNo <= 1) // 南都华能新疆项目传IO数据给后台(一个集装箱有两个IO模块，配置不一样) added 2022-8-2
    //  pComReg->usComInputRegVal[82] = KgGlobalData::ms_dryData.DIVal;
	//else
	//	pComReg->usComInputRegVal[83] = KgGlobalData::ms_dryData.DIVal;
#ifdef PGKS_PRJ // added 2022-9-7
	quint16 replyState[6] = {0,0,0,0,0,0};
	//汇流开关反馈
	//可燃气体报警反馈
	//空调反馈
	//排风扇反馈
	//if (0 == g_bReadDiFlag)// 还未读取到DI //if(!KgGlobalData::ms_dryData.bReadDiFlag)
	if(0 == KgGlobalData::ms_dryData.readDiCount)
	{
		 writeKgLogfile("has not read DI\n");
		 replyState[0] = 2; // 0：断开，1：闭合 2：未读取
		 replyState[1] = 2; // 0：正常，1：报警 2：未读取
		 replyState[2] = 2; // 0：断开，1：闭合 2：未读取
		 replyState[3] = 2; // 0：断开，1：闭合 2：未读取
		 replyState[4] = 2; // 0：断开，1：闭合 2：未读取
		 replyState[5] = 2; // 0：断开，1：闭合 2：未读取
	}
	else
	{
		 if ((0x01 & KgGlobalData::ms_dryData.DIVal) > 0)// 反馈1  汇流开关反馈
		 {
		  	 replyState[0] = 1;
		 }
		 if ((0x02 & KgGlobalData::ms_dryData.DIVal) > 0)// 反馈2 可燃气体报警反馈
		 {
		  	 replyState[1] = 1;
		 }
		 if ((0x04 & KgGlobalData::ms_dryData.DIVal) > 0)// 反馈3 空调反馈
		 {
		  	 replyState[2] = 1;
		 }
		 if ((0x08 & KgGlobalData::ms_dryData.DIVal) > 0)// 反馈4 排风扇反馈
		 {
		  	 replyState[3] = 1;
		 }
		 if ((0x10 & KgGlobalData::ms_dryData.DIVal) > 0)//
		 {
		  	 replyState[4] = 1;
		 }
		 if ((0x20 & KgGlobalData::ms_dryData.DIVal) > 0)//
		 {
		  	 replyState[5] = 1;
		 }
		 
	}
	
	pos = 49;//50;// 70;//存储串口继电器的DI数据
	pComReg->usComInputRegVal[pos++] = KgGlobalData::ms_dryData.failedCount;
	pComReg->usComInputRegVal[pos++] = replyState[0];
	pComReg->usComInputRegVal[pos++] = replyState[1];
	pComReg->usComInputRegVal[pos++] = replyState[2];
	pComReg->usComInputRegVal[pos++] = replyState[3];
	pComReg->usComInputRegVal[pos++] = replyState[4];
	pComReg->usComInputRegVal[pos++] = replyState[5];
#endif

#ifdef LSZH_PRJ
	 lszhUpdateRtdb(pStack,replyState);
#endif
}

//执行sql语句
int InnerExecDbQuery(QString strSql, QString &strError, bool bUsedLock)
{ 
	QSqlQuery sqlQuery(g_db);
	int ret = sqlQuery.exec(strSql);

	bool hasError = false;
	if(0==ret)//执行失败
	{
	   strError =sqlQuery.lastError().text();
	   //writeKgLogfile(strError);
	}
	return ret;
}


//执行sql语句
int ExecDbQuery(QString strSql, QString &strError)
{
    int testVal = 0;
	int ret = InnerExecDbQuery(strSql, strError,true);
	return ret;
}

QString   g_startDt;
int       g_bankNo = 0;
int       g_boxNo = 0;
void saveFireAlarmToDb(int fireBankNo, int fireBoxNo)
{
   QString strSql;
   QDateTime currentDt=QDateTime::currentDateTime();
   QString   startDt = currentDt.toString("yyyy-MM-dd hh:mm:ss");

  //fireBankNo = 3;
  //fireBoxNo = 6;
  strSql = QString("insert into tblAlarm values(null,'%1',null,%2,%3,%4,%5,%6,%7,%8)")
  	.arg(startDt).arg(ALARM_TYPE_FIRE_ALARM).arg(fireBankNo+1).arg(fireBoxNo)
  	.arg(1).arg(0).arg(999).arg(999);
  
   QString strError;
   if (!::ExecDbQuery(strSql,strError))
   {
      QString strHint =QString("save fire alarm data to db failed:%1, result:%2")
	  	.arg(strSql).arg(strError);
 	  writeKgLogfile(strHint);
   }
   else
   {
      QString strHint =QString("save fire alarm data to db OK:%1").arg(strSql);
 	  writeKgLogfile(strHint);
	  g_startDt = startDt;
	  g_bankNo = fireBankNo;
	  g_boxNo = fireBoxNo;
   }
}

void updateAlarmOverToDb()
{
   QString strSql;
  QDateTime currentDt=QDateTime::currentDateTime();
  QString   endDt = currentDt.toString("yyyy-MM-dd hh:mm:ss");
  
  strSql = QString("update tblAlarm set endDT='%1' where bankNo='%2' and cellNo='%3' and startDT='%4'")
  	.arg(endDt).arg(g_bankNo+1).arg(g_boxNo)
  	.arg(g_startDt);
  
   QString strError;
   if (!::ExecDbQuery(strSql,strError))
   {
      QString strHint =QString("update fire alarm endtime to db failed:%1, result:%2")
	  	.arg(strSql).arg(strError);
 	  writeKgLogfile(strHint);
   }
   else
   {
      QString strHint =QString("update fire alarm endtime to db OK:%1").arg(strSql);
 	  writeKgLogfile(strHint);
   }
}

void saveLogToBaDb(QString strLog)
{
  QString strSql;
  QDateTime currentDt=QDateTime::currentDateTime();
  QString   startDt = currentDt.toString("yyyy-MM-dd hh:mm:ss");

  //writeKgLogfile(strLog, true);

  //fireBankNo = 3;
  //fireBoxNo = 6;
  strSql = QString("insert into tbllog values(null,'%1',%2,'%3')")
  	.arg(startDt).arg(1).arg(strLog);
  
   QString strError;
   if (!::ExecDbQuery(strSql,strError))
   {
      QString strHint =QString("save log to db failed:%1, result:%2")
	  	.arg(strSql).arg(strError);
 	  writeKgLogfile(strHint);
   }
   else
   {
      QString strHint =QString("save log to db OK:%1").arg(strSql);
 	  writeKgLogfile(strHint);
   }
}


void saveBcLogToBaDb(QString strLog)
{
  QString strSql;
  QDateTime currentDt=QDateTime::currentDateTime();
  QString   startDt = currentDt.toString("yyyy-MM-dd hh:mm:ss");

  writeKgBcLogfile(strLog, true);

  //fireBankNo = 3;
  //fireBoxNo = 6;
  strSql = QString("insert into tbllog values(null,'%1',%2,'%3')")
  	.arg(startDt).arg(1).arg(strLog);
  
   QString strError;
   if (!::ExecDbQuery(strSql,strError))
   {
      QString strHint =QString("save log to db failed:%1, result:%2")
	  	.arg(strSql).arg(strError);
 	  writeKgLogfile(strHint);
   }
   else
   {
      QString strHint =QString("save log to db OK:%1").arg(strSql);
 	  writeKgLogfile(strHint);
   }
}
//  判断电池组是否参与运算//added 2020-6-12
int isBankInStack(int bankNo)
{
	CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
	if (!pStack)
	{
	    return  0;
	}
	quint16 usStackCfgInfo = pStack->usStackCfgInfo;

	int ret = 0;
	int maskVal = 0x01 << bankNo;
	if ((usStackCfgInfo & maskVal) > 0) // 该组参与运算
	{
		ret	= 1;
	}

	//printf("=======usStackCfgInfo:%d, bank:%d, ret:%d\n",
	//	usStackCfgInfo, bankNo, ret);

	return ret;
}

void   keepContCtrlOpened(int stackState, int hlkgState)
{
	for(int grp = 0; grp < KgGlobalData::ms_installBankNum; ++grp)
	{
	    CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(grp);
		if (!pBank)
		{
		   continue;
		}

		if (isBankInStack(grp))
		{
			if (4 == stackState && 1 == hlkgState) // 系统故障，且汇流开关为闭合状态
			{
				if (0 == pBank->usDI1) // 正接触器为断开状态
			    {
			        pBank->usEMSContCtrlPos = 2; // 2 - 保持断开
			    }
				if (0 == pBank->usDI2) // 负接触器为断开状态 
			    {
			        pBank->usEMSContCtrlNeg = 2; // 2 - 保持断开
			    }
			}
			else 
			{
				   pBank->usEMSContCtrlPos = 0; // 0 - BMS控制
				   pBank->usEMSContCtrlNeg = 0; // 0 - BMS控制
			}
		}
    }
}

int isChLang()
{
	int ret = 0;
	CBattStack *pStack = KgGlobalData::ms_pRTDB->getStack(0);
	if (pStack)
	{
	   if(0 == pStack->usLang) // 语言        0 - 中文   1 - 英文         Misc.ini
		{
			ret =  1;
		}
	}

	return ret;
}

int isBankAlarm()// 0：正常 1：报警 //added 2021-5-30
{
	int ret = 0;
    for(int i = 0; i < KgGlobalData::ms_installBankNum; ++i)
   	{
   	    CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(i);
		if (0 == pBank || 0 == isBankInStack(i))
		{
			continue;
		}
		/*
		char aChgCurUpLimitAlarm;		 // 充电电流上限告警               24 
		char aDchgCurUpLimitAlarm;		 // 放电电流上限告警               25
		char aSglVolUpLimitAlarm;	     // 单体电压上限告警	           26
		char aSglVolDownLimitAlarm;	     // 单体电压下限告警	           27	
		char aChgTempUpLimitAlarm;	     // 充电温度上限告警	           28	
		char aChgTempDownLimitAlarm;	 // 充电温度下限告警               29
		char aDchgTempUpLimitAlarm;	     // 放电温度上限告警	           30	
		char aDchgTempDownLimitAlarm;	 // 放电温度下限告警               31
		char aSglTempUpLimitAlarm;	     // 单体温度上限告警	           32	
		char aSglTempDownLimitAlarm;	 // 单体温度下限告警               33
		//char aEnvTempUpLimitAlarm;	// 环境温度上限告警	           34
		//char aEnvTempDownLimitAlarm;	 // 环境温度下限告警	           35
		char aPowerLineTempUpLimitAlarm; // 动力线温度上限告警	           36
		//char aBankSocUpLimitAlarm;	 // SOC超上限告警		           37
		//char aBankSocDownLimitAlarm;	 // SOC超下限告警		           38
		char aPosResDownLimitAlarm;		 // 正极绝缘内阻下限告警           39
		char aNegResDownLimitAlarm;		 // 负极绝缘内阻下限告警           40
		char aPackVolDiffUpLimitAlarm;	 // 箱压差上限告警                 41
		char aPackTempDiffUpLimitAlarm;	 // 箱温差上限告警                 42
		*/

		if(pBank->aChgCurUpLimitAlarm > 0 ||
			pBank->aDchgCurUpLimitAlarm > 0 ||
			pBank->aSglVolUpLimitAlarm > 0 ||
			pBank->aSglVolDownLimitAlarm > 0 ||
			pBank->aChgTempUpLimitAlarm > 0 ||
			pBank->aChgTempDownLimitAlarm > 0 ||
			pBank->aDchgTempUpLimitAlarm > 0 ||
			pBank->aDchgTempDownLimitAlarm > 0 ||
			pBank->aSglTempUpLimitAlarm > 0 ||
			pBank->aSglTempUpLimitAlarm > 0 ||
			pBank->aPowerLineTempUpLimitAlarm > 0 ||
			pBank->aPosResDownLimitAlarm > 0 ||
			pBank->aNegResDownLimitAlarm > 0 ||
			pBank->aPackVolDiffUpLimitAlarm > 0 ||
			pBank->aPackTempDiffUpLimitAlarm > 0)
		    {
		       ret = 1;
			   break;
		    }
    }
	
	return ret;
}

bool hasVolDownPort() // 有电压欠压保护
{
   bool iHasProt = false;
   
   for(int k = 0; k < KgGlobalData::ms_installBankNum; ++k)
   	{
   	   CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(k);

	   if(pBank && isBankInStack(k))
	   {
	      if (pBank->aBankVolDownLimitProt || pBank->aSglVolDownLimitProt)
		  	{
		  	    iHasProt = true;
				break;
		  	}
	   }
   	}

   return iHasProt;
}

// 控制DO闭合
void openDos(quint16 &IOCtrl, QList<int> doList)
{
	for (int k = 0; k < doList.size(); ++k) 
	{
		int doIndex = doList[k];
		IOCtrl |= (1 << doIndex);
	}
}

// 控制DO断开
void closeDos(quint16 &IOCtrl, QList<int> doList)
{
	for (int k = 0; k < doList.size(); ++k)
	{
		int doIndex = doList[k];
		IOCtrl &= ~(1 << doIndex);
	}
}

void getInstallInfo()
{
	if(KgGlobalData::ms_pStack)
	{
		int usInstallBankNum = KgGlobalData::ms_pStack->usInstallBankNum;
		int usBankNumInStack = KgGlobalData::ms_pStack->usBankNumInStack;// 从rtdb中获取
		if(usInstallBankNum > MAX_BANK_NUM)
		{
			usInstallBankNum = MAX_BANK_NUM;
		}

		if(usBankNumInStack > MAX_BANK_NUM)
		{
			usBankNumInStack = MAX_BANK_NUM;
		}

		KgGlobalData::ms_installBankNum = usInstallBankNum;
		KgGlobalData::ms_bankNumInStack = usBankNumInStack;
	}
}

int isBoxVolTempDiffAlarm()
{
	int ret = 0;
    for(int i = 0; i < KgGlobalData::ms_installBankNum; ++i)
   	{
   	    CBattBank *pBank = KgGlobalData::ms_pRTDB->getBank(i);
		if (0 == pBank || 0 == isBankInStack(i))
		{
			continue;
		}

		if(pBank->aPackVolDiffUpLimitAlarm + pBank->aPackTempDiffUpLimitAlarm + 
			pBank->aPackVolDiffUpLimitProt + pBank->aPackTempDiffUpLimitProt > 0)  // 箱压差上限告警 // 箱温差上限告警  
		{
			ret = 1;
		}
	}

	return ret;
}

//QString strTestLog;
// added 2023-8-22
QString parseDIName(QString strUtf8)
{
	if(2 == KgGlobalData::ms_textCode)// 中文
	{
		return strUtf8;
	}

	if(!isChLang())
	{
		return strUtf8;
	}
	
	char buf[200];
	int k = 0;
	int pos = 0;

	if(strUtf8.length() < 2)
	{
		return QString();
	}
	
	// http://www.mytju.com/classcode/tools/encode_utf8.asp
	while((pos+2) <= strUtf8.length())
	{
		QString str = strUtf8.mid(pos, 2);
		pos += 2;
		buf[k++] = str.toInt(0,16);
	}
	
	QString str = QString::fromUtf8 (buf, k);
	//strTestLog = str;
	return str;
	
	/*
	buf[k++] = 0xE6;// 正
	buf[k++] = 0xAD;
	buf[k++] = 0xA3;

	buf[k++] = 0xE5;// 常
	buf[k++] = 0xB8;
	buf[k++] = 0xB8;
	QString str = QString::fromUtf8 (buf, 6);
	*/
}

QString getOverName()
{
	QString str;
	
	if(isChLang()) 
		str = kgConvert("结束");
	else
	    str = QString(" over");

	return str;	
}

void setStgName(XFStrategy &obj, QString diName, QString diOverName)
{
	obj.diName = diName;
	obj.diOverName = diOverName;
}

// added 2023-9-16
void initResAlarm(int diIndex, int resNo, XFStrategy &resStg, QString strAlarmName, QString strAlarmOverName)
{
	if(strAlarmName.length() >= 3)// 有指定告警发生名称 // added 2023-8-22
	{
		resStg.diName = parseDIName(strAlarmName) + QString("(DI%1).").arg(diIndex+0);
		if(strAlarmOverName.length() >= 3)// 有指定告警结束名称 // added 2023-8-23
		{
			// resStg.diOverName = parseDIName(strAlarmOverName) + QString("(DI%1).").arg(diIndex+1);
			resStg.diOverName = parseDIName(strAlarmOverName) + QString(".");
		}
		else
		{
			// resStg.diOverName = parseDIName(strAlarmName) + getOverName() + QString("(DI%1).").arg(diIndex+1) ;
			resStg.diOverName = parseDIName(strAlarmName) + getOverName() + QString(".");
		}
	}
	else
	{
	    if(isChLang())
	    {
			resStg.diName = kgConvert("%1#备用告警(DI%2).").arg(resNo).arg(diIndex+0);
			//resStg.diOverName = kgConvert("%1#备用告警结束(DI%2).").arg(resNo).arg(diIndex+1);
			resStg.diOverName = kgConvert("%1#备用告警结束.").arg(resNo);
	    }
		else
		{
		   resStg.diName = QString("%1# resvered alarm(DI%2).").arg(resNo).arg(diIndex+0);
		   //resStg.diOverName = QString("%1# resvered alarm over(DI%2).").arg(resNo).arg(diIndex+1);
		   resStg.diOverName = QString("%1# resvered alarm over.").arg(resNo);
		}
	}
	writeKgLogfile(QString("DI%1 is %2# resvered state node.").arg(diIndex+1).arg(resNo));
}

void readFileDIDOConfig()
{
	int i;
	QSettings setApp("../ini/xnbmsio.ini", QSettings::IniFormat); // 2023-11-15
	printf("readFileDIDOConfig\n");

	for(i = 0; i <	KgGlobalData::ms_devDoCount; ++i) // read DO Strategy
	{
		int iStrategy = setApp.value(QString("DOCtrl/DO%1Strategy").arg(i+1),"0").toInt();
		if(i > 0)
		{
			KgGlobalData::ms_IOConfigStr += "-";
		}
		KgGlobalData::ms_IOConfigStr += QString("%1").arg(iStrategy);
		
		if (iStrategy > 0)
		{
			DOStrategy stg = {i, iStrategy};
			if (1 == iStrategy)			// 1:故障灯或故障干结点
			{
				KgGlobalData::ms_gzCtrlList.append(stg);
				writeKgLogfile(QString("DO%1 is fault node.").arg(i+1));
			}
			else if (2 == iStrategy)	// 2:禁充干结点
			{
				KgGlobalData::ms_phbChgList.append(stg);
				writeKgLogfile(QString("DO%1 is prohibit charge node.").arg(i+1));
			}
			else if (3 == iStrategy)	// 3:禁放干结点
			{
				KgGlobalData::ms_phbDischgList.append(stg);
				writeKgLogfile(QString("DO%1 is prohibit discharge node.").arg(i+1));
			}
			else if (6 == iStrategy)	// 6:运行干结点
			{
				KgGlobalData::ms_runCtrlList.append(stg);
				writeKgLogfile(QString("DO%1 is run node.").arg(i+1));
			}
			else if (8 == iStrategy)	// 8:防雷动作干结点
			{
				KgGlobalData::ms_tdStrategy.xfCtrlList.append(stg);
				writeKgLogfile(QString("DO%1 is thunder motion node.").arg(i+1));
			}
			else if (9 == iStrategy)	// 9:消防动作干结点
			{
				KgGlobalData::ms_xfStrategy.xfCtrlList.append(stg);
				writeKgLogfile(QString("DO%1 is XF motion node.").arg(i+1));
			}
			else if (10 == iStrategy)	// 10:告警干结点
			{
				KgGlobalData::ms_alarmCtrlList.append(stg); // modified 2021-5-30
				writeKgLogfile(QString("DO%1 is alarm node.").arg(i+1));
			}
			else if (16 == iStrategy)	// 16:常亮灯 added 2023-11-16
			{
				KgGlobalData::ms_allLightCtrlList.append(stg);
				writeKgLogfile(QString("DO%1 is all right node.").arg(i+1));
			}
			else if (20 == iStrategy)	// 20:充电接触器驱动
			{
				KgGlobalData::ms_chgDriveList.append(stg); // added 2021-9-9
				writeKgLogfile(QString("DO%1 is charge drive node.").arg(i+1));
			}
			else if (21 == iStrategy)	// 21:放电接触器驱动
			{
				KgGlobalData::ms_dchgDriveList.append(stg);  // added 2021-9-9
				writeKgLogfile(QString("DO%1 is discharge drive node.").arg(i+1));
			}
			else if (22 == iStrategy)	// 22:BMS-EMS通信故障
			{
				KgGlobalData::ms_bmsEmsCommFaultList.append(stg);  // added 2022-7-11
				writeKgLogfile(QString("DO%1 is BMS-EMS communicate fault node.").arg(i+1));
			}
			else if (23 == iStrategy)	// 23:消防喷洒动作干结点 added 2022-12-10
			{
				KgGlobalData::ms_xfSprayStrategy.xfCtrlList.append(stg);  
				writeKgLogfile(QString("DO%1 is XF spray motion node.").arg(i+1));
			}
			else if (24 == iStrategy)	// 24:并网故障干结点 added 2023-6-14
			{
				KgGlobalData::ms_bwGzCtrlList.append(stg);  
				writeKgLogfile(QString("DO%1 is bw error node.").arg(i+1));
			}
			else if (101 == iStrategy) // 101:汇流开关合闸干结点 
			{
				KgGlobalData::ms_hlkgStrategy.hzDoList.append(i);
				writeKgLogfile(QString("DO%1 is HZ node.").arg(i+1));
			}
			else if (102 == iStrategy) // 102:汇流开关分闸干结点
			{
				KgGlobalData::ms_hlkgStrategy.fzDoList.append(i);
				writeKgLogfile(QString("DO%1 is FZ node.").arg(i+1));
			}
			else if (103 == iStrategy) // 103:低电压保护时分闸干结点
			{
				KgGlobalData::ms_hlkgStrategy.volDownProtFzDoList.append(i);
				writeKgLogfile(QString("DO%1 is Vol Down Prot FZ node.").arg(i+1));
			}
			else if (109 == iStrategy) // 109:消防脱扣干结点 // added 2021-10-29 
			{
				KgGlobalData::ms_hlkgStrategy.xfTkDoList.append(i);
				writeKgLogfile(QString("DO%1 is XF FZ node.").arg(i+1));
			}
			else if (110 == iStrategy)	// 110:消防喷洒脱扣干结点 added 2022-12-10
			{
				KgGlobalData::ms_hlkgStrategy.xfSprayTkDoList.append(i);  
				writeKgLogfile(QString("DO%1 is XF spray FZ motion node.").arg(i+1));
			}
			else
				;
		}
	}
	
    KgGlobalData::ms_IOConfigStr += QString(", DI:");
	for(i = 0; i <	KgGlobalData::ms_devDiCount; ++i)// read DI Strategy
	{
		int iStrategy = setApp.value(QString("DIColl/DI%1Strategy").arg(i+1),"0").toInt();
		int iAlarmValue = setApp.value(QString("DIColl/DI%1AlarmValue").arg(i+1),"1").toInt(); 
		QString strDIName = setApp.value(QString("DIColl/DI%1Name").arg(i+1),"").toString(); 
		QString strDIOverName = setApp.value(QString("DIColl/DI%1OverName").arg(i+1),"").toString(); 
		
		//  0 - 常闭,为0(干结点断开)时发生告警 
		//  1 - 常开,为1(干结点闭合)时发生告警 (常用)
		if(i > 0)
		{
			KgGlobalData::ms_IOConfigStr += "-";
		}
		KgGlobalData::ms_IOConfigStr += QString("%1").arg(iStrategy);
		KgGlobalData::ms_diAlarmVals.append(iAlarmValue);
		
		if (iStrategy > 0)
		{
			DIStrategy stg = {i, iStrategy};

			if (1 == iStrategy)		// 1:汇流开关反馈
			{	
			    //DI_STU diItem = {i,1};
			    DI_STU diItem = {i,iAlarmValue};
				//KgGlobalData::ms_hlkgStrategy.diCfg.diIndex = i;
				//KgGlobalData::ms_hlkgStrategy.diCfg.alarmValue = 1;//iAlarmValue; // modified 2021-9-9
				KgGlobalData::ms_hlkgStrategy.diCfgList.append(diItem);
				writeKgLogfile(QString("DI%1 is hzkg state node.").arg(i+1));	
			}
			else if (3 == iStrategy)// 3:主断路器反馈
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_mainSwitchStrategy.diList.append(stu); // added 2024-1-23
				writeKgLogfile(QString("DI%1 is mainSwitch state node.").arg(i+1));
			}
			else if (2 == iStrategy)// 2:隔离开关反馈
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_isolSwitchStrategy.diList.append(stu);
				writeKgLogfile(QString("DI%1 is isolSwitch state node.").arg(i+1));
			}
			else if (8 == iStrategy)// 8:防雷采集干结点 
			{
				//KgGlobalData::ms_tdStrategy.diIndex = i;
				//KgGlobalData::ms_tdStrategy.alarmValue = iAlarmValue;
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_tdStrategy.diList.append(stu);
				writeKgLogfile(QString("DI%1 is thunder state node.").arg(i+1));
			}
			else if (108 == iStrategy)// 18:#2防雷采集干结点  ***************
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_tdStrategySec.diList.append(stu);
				writeKgLogfile(QString("DI%1 is #2thunder state node.").arg(i+1));
			}
			else if (9 == iStrategy)// 9:消防采集干结点 
			{
				//KgGlobalData::ms_xfStrategy.diIndex = i;
				//KgGlobalData::ms_xfStrategy.alarmValue = iAlarmValue;
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_xfStrategy.diList.append(stu);
				if(strDIName.length() >= 3)// added 2024-1-24
				{
					// KgGlobalData::ms_xfStrategy.diName = parseDIName(strDIName)+ QString("(DI%1).").arg(i+1);
					KgGlobalData::ms_xfStrategy.diName = parseDIName(strDIName);
					if(strDIOverName.length() >= 3)
					{
						KgGlobalData::ms_xfStrategy.diOverName = parseDIName(strDIOverName);
					}
				}
				writeKgLogfile(QString("DI%1 is XF state node.").arg(i+1));
			}
			else if (10 == iStrategy)// 10:水浸采集干结点 
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_waterStrategy.diList.append(stu);
				writeKgLogfile(QString("DI%1 is Water come state node.").arg(i+1));
			}
			else if (110 == iStrategy)// 100:#2水浸采集干结点 ***************
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_waterStrategySec.diList.append(stu);
				writeKgLogfile(QString("DI%1 is #2Water come state node.").arg(i+1));
			}
			else if (11 == iStrategy)// 11:急停信号采集干结点 
			{
				//KgGlobalData::ms_emgStopStrategy.diIndex = i;
				//KgGlobalData::ms_emgStopStrategy.alarmValue = iAlarmValue;
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_emgStopStrategy.diList.append(stu);
				writeKgLogfile(QString("DI%1 is emergency stop node.").arg(i+1));
			}
			else if (111 == iStrategy)// 111:#2急停信号采集干结点 ***************
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_emgStopStrategySec.diList.append(stu);
				writeKgLogfile(QString("DI%1 is #2emergency stop node.").arg(i+1));
			}
			else if (12 == iStrategy)// 12:可燃气体采集干结点 
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_combusGasStrategy.diList.append(stu);
				writeKgLogfile(QString("DI%1 is combustible gas node.").arg(i+1));
			}
			// added 2022-3-27
			else if (13 == iStrategy)// 13:熔断器采集反馈干结点 
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_fuseStrategy.diList.append(stu);
				writeKgLogfile(QString("DI%1 is fuse node.").arg(i+1));
			}
			// added 2022-4-6
			else if (14 == iStrategy)// 14:消防释放信号
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_xfMotionStrategy.diList.append(stu);
				writeKgLogfile(QString("DI%1 is XF motion node.").arg(i+1));
			}
			else if (20 == iStrategy)	// 20:充电接触器驱动信号
			{
				KgGlobalData::ms_diIndexChgDrive = i; // added 2021-9-9
				writeKgLogfile(QString("DI%1 is charge drive FK node.").arg(i+1));
			}
			else if (21 == iStrategy)	// 21:放电接触器驱动信号
			{
				KgGlobalData::ms_diIndexDchgDrive = i; // added 2021-9-9
				writeKgLogfile(QString("DI%1 is discharge drive FK node.").arg(i+1));
			}
			else if (22 == iStrategy)	// 22:消防预警信号
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_xfWarmStrategy.diList.append(stu);// added 2022-6-8
				if(strDIName.length() >= 3)// added 2024-1-24
				{
					// KgGlobalData::ms_xfWarmStrategy.diName = parseDIName(strDIName)+ QString("(DI%1).").arg(i+1);
					KgGlobalData::ms_xfWarmStrategy.diName = parseDIName(strDIName);
					if(strDIOverName.length() >= 3)
					{
						KgGlobalData::ms_xfWarmStrategy.diOverName = parseDIName(strDIOverName);
					}
				}
				writeKgLogfile(QString("DI%1 is XF Warm node.").arg(i+1));
			}
			else if (23 == iStrategy)	// 23:UPS告警信号
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_upsAlmStrategy.diList.append(stu);
				writeKgLogfile(QString("DI%1 is Ups node.").arg(i+1));
			}
			/*
			else if (24 == iStrategy)	// 24:门禁告警信号
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_doorAlmStrategy.diList.append(stu);
				if(strDIName.length() >= 3)// added 2023-8-22
				{
					KgGlobalData::ms_doorAlmStrategy.diName = parseDIName(strDIName)+ QString("(DI%1).").arg(i+1);
					if(strDIOverName.length() >= 3)// added 2023-8-23
					{
						KgGlobalData::ms_doorAlmStrategy.diOverName = parseDIName(strDIOverName) + QString("(DI%1).").arg(i+1);
					}
					else
					{
						KgGlobalData::ms_doorAlmStrategy.diOverName = parseDIName(strDIName)+ getOverName() + QString("(DI%1).").arg(i+1);
					}
				}
				else
				{
					if(isChLang())
					{
						KgGlobalData::ms_doorAlmStrategy.diName = kgConvert("门禁告警") + QString("(DI%1).").arg(i+1);
						KgGlobalData::ms_doorAlmStrategy.diOverName = kgConvert("门禁告警") + QString("(DI%1)").arg(i+1) + kgConvert("结束.");
					}
					else
					{
						KgGlobalData::ms_doorAlmStrategy.diName = QString("Door alarm") + QString("(DI%1).").arg(i+1);
						KgGlobalData::ms_doorAlmStrategy.diOverName = QString("Door alarm") + QString("(DI%1)").arg(i+1) + QString(" over.");
					}
				}
				writeKgLogfile(QString("DI%1 is Door node.").arg(i+1));
			}
			else if (34 == iStrategy)	// 34:门禁告警信号2   added 2023-5-4
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_doorAlmStrategySec.diList.append(stu);
				if(strDIName.length() >= 3)
				{
					KgGlobalData::ms_doorAlmStrategySec.diName = parseDIName(strDIName) + QString("(DI%1).").arg(i+1);
					if(strDIOverName.length() >= 3)// added 2023-8-23
					{
						KgGlobalData::ms_doorAlmStrategySec.diOverName = parseDIName(strDIOverName) + QString("(DI%1).").arg(i+1);
					}
					else
					{
						KgGlobalData::ms_doorAlmStrategySec.diOverName = parseDIName(strDIName) + getOverName() + QString("(DI%1).").arg(i+1);
					}
				}
				else
				{
					if(isChLang())
					{
						KgGlobalData::ms_doorAlmStrategySec.diName = kgConvert("2#门禁告警") + QString("(DI%1).").arg(i+1);
						KgGlobalData::ms_doorAlmStrategySec.diOverName = kgConvert("2#门禁告警") + QString("(DI%1)").arg(i+1) + kgConvert("结束.");
					}
					else
					{
						KgGlobalData::ms_doorAlmStrategySec.diName = QString("2#Door alarm") + QString("(DI%1).").arg(i+1);
						KgGlobalData::ms_doorAlmStrategySec.diOverName = QString("2#Door alarm") + QString("(DI%1)").arg(i+1) + QString(" over.");
					}
				}
				writeKgLogfile(QString("DI%1 is Door Sec node.").arg(i+1));
			}
			*/
			else if (24 == iStrategy)	// 24:门禁告警信号
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_doorAlmStrategy.diList.append(stu);
				if(strDIName.length() >= 3)// added 2023-8-22
				{
					KgGlobalData::ms_doorAlmStrategy.diName = parseDIName(strDIName)+ QString("(DI%1).").arg(i+1);
					if(strDIOverName.length() >= 3)// added 2023-8-23
					{
						// modified 2024-1-24
						//KgGlobalData::ms_doorAlmStrategy.diOverName = parseDIName(strDIOverName) + QString("(DI%1).").arg(i+1);
						KgGlobalData::ms_doorAlmStrategy.diOverName = parseDIName(strDIOverName) + QString(".");
					}
					else
					{
						//KgGlobalData::ms_doorAlmStrategy.diOverName = parseDIName(strDIName) + QString("(DI%1)").arg(i+1) + getOverName();
						KgGlobalData::ms_doorAlmStrategy.diOverName = parseDIName(strDIName) + getOverName() + QString(".");
					}
				}
				else
				{
					if(isChLang())
					{
						KgGlobalData::ms_doorAlmStrategy.diName = kgConvert("门禁告警") + QString("(DI%1).").arg(i+1);
						//KgGlobalData::ms_doorAlmStrategy.diOverName = QString("门禁告警") + QString("(DI%1)").arg(i+1) + QString("结束.");
						KgGlobalData::ms_doorAlmStrategy.diOverName = kgConvert("门禁告警") + kgConvert("结束.");
					}
					else
					{
						KgGlobalData::ms_doorAlmStrategy.diName = QString("Door alarm") + QString("(DI%1).").arg(i+1);
						//KgGlobalData::ms_doorAlmStrategy.diOverName = QString("Door alarm") + QString("(DI%1)").arg(i+1) + QString(" over.");
						KgGlobalData::ms_doorAlmStrategy.diOverName = QString("Door alarm")+ QString(" over.");
					}
				}
				writeKgLogfile(QString("DI%1 is Door node.").arg(i+1));
			}
			else if (34 == iStrategy)	// 34:门禁告警信号2   added 2023-5-4
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_doorAlmStrategySec.diList.append(stu);
				if(strDIName.length() >= 3)
				{
					KgGlobalData::ms_doorAlmStrategySec.diName = parseDIName(strDIName) + QString("(DI%1).").arg(i+1);
					if(strDIOverName.length() >= 3)// added 2023-8-23
					{
						// KgGlobalData::ms_doorAlmStrategySec.diOverName = parseDIName(strDIOverName) + QString("(DI%1).").arg(i+1);
						KgGlobalData::ms_doorAlmStrategySec.diOverName = parseDIName(strDIOverName) + QString(".");
					}
					else
					{
						// KgGlobalData::ms_doorAlmStrategySec.diOverName = parseDIName(strDIName) + QString("(DI%1)").arg(i+1)+ getOverName(); 
						KgGlobalData::ms_doorAlmStrategySec.diOverName = parseDIName(strDIName) + getOverName() + QString(".");
					}
				}
				else
				{
					if(isChLang())
					{
						KgGlobalData::ms_doorAlmStrategySec.diName = kgConvert("2#门禁告警") + QString("(DI%1).").arg(i+1);
						// KgGlobalData::ms_doorAlmStrategySec.diOverName = QString("2#门禁告警") + QString("(DI%1)").arg(i+1) + QString("结束.");
						KgGlobalData::ms_doorAlmStrategySec.diOverName = kgConvert("2#门禁告警")  + kgConvert("结束.");
						
					}
					else
					{
						KgGlobalData::ms_doorAlmStrategySec.diName = QString("2#Door alarm") + QString("(DI%1).").arg(i+1);
						// KgGlobalData::ms_doorAlmStrategySec.diOverName = QString("2#Door alarm") + QString("(DI%1)").arg(i+1) + QString(" over.");
						KgGlobalData::ms_doorAlmStrategySec.diOverName = QString("2#Door alarm") + QString(" over.");
					}
				}
				writeKgLogfile(QString("DI%1 is Door Sec node.").arg(i+1));
			}
			else if (25 == iStrategy)	// 25:消防喷洒信号 added 2022-12-10
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_xfSprayStrategy.diList.append(stu);
				if(strDIName.length() >= 3)// added 2024-1-24
				{
					// KgGlobalData::ms_xfSprayStrategy.diName = parseDIName(strDIName)+ QString("(DI%1).").arg(i+1);
					KgGlobalData::ms_xfSprayStrategy.diName = parseDIName(strDIName);
					if(strDIOverName.length() >= 3)
					{
						KgGlobalData::ms_xfSprayStrategy.diOverName = parseDIName(strDIOverName);
					}
				}
				writeKgLogfile(QString("DI%1 is XF Spray state node.").arg(i+1));
			}
			else if (26 == iStrategy)	// 26:消防故障 added 2022-12-21
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_xfFaultStrategy.diList.append(stu);
				writeKgLogfile(QString("DI%1 is XF Fault state node.").arg(i+1));
			}
			else if (27 == iStrategy)	// 27:消防手动/自动 added 2023-11-9
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_xfManuAutoStrategy.diList.append(stu);
				writeKgLogfile(QString("DI%1 is XF manu/auto mode node.").arg(i+1));
			}
			else if (30 == iStrategy)	// 30:市电断电 added 2023-11-9
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_elecPowerOffStrategy.diList.append(stu);
				writeKgLogfile(QString("DI%1 is Elec power off node.").arg(i+1));
			}
			else if (31 == iStrategy)	// 31:BMS就地 added 2023-12-25
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_bmsLocalStrategy.diList.append(stu);
				writeKgLogfile(QString("DI%1 is Bms local node.").arg(i+1));
			}
			else if (32 == iStrategy)	// 32:BMS远方
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_bmsRemmoteStrategy.diList.append(stu);
				writeKgLogfile(QString("DI%1 is Bms remote node.").arg(i+1));
			}
			else if (41 == iStrategy)	// 41:空调机组故障 added 2024-2-3
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_acFaultStrategy.diList.append(stu);
				writeKgLogfile(QString("DI%1 is AC fault node."));
			}
			else if (42 == iStrategy)	// 42:液冷机组故障 added 2024-2-3
			{
				DI_STU stu = {i,iAlarmValue};
				KgGlobalData::ms_lqFaultStrategy.diList.append(stu);
				writeKgLogfile(QString("DI%1 is LQ fault node."));
			}
			else if (51 == iStrategy)	// 51:备用信号 added 2023-8-19
			{
				DI_STU stu = {i,iAlarmValue};
				XFStrategy &resStg = KgGlobalData::ms_resStrategy[0];
				resStg.diList.append(stu);
				int retNo = iStrategy - 50;
				initResAlarm(i, retNo, resStg, strDIName, strDIOverName);
			}
			else if (52 == iStrategy)	// 52:备用信号
			{
				DI_STU stu = {i,iAlarmValue};
				XFStrategy &resStg = KgGlobalData::ms_resStrategy[1];
				resStg.diList.append(stu);
				int retNo = iStrategy - 50;
				initResAlarm(i, retNo, resStg, strDIName, strDIOverName);
			}
			else if (53 == iStrategy)	// 53:备用信号
			{
				DI_STU stu = {i,iAlarmValue};
				XFStrategy &resStg = KgGlobalData::ms_resStrategy[2];
				resStg.diList.append(stu);
				int retNo = iStrategy - 50;
				initResAlarm(i, retNo, resStg, strDIName, strDIOverName);
			}
			else if (54 == iStrategy)	// 54:备用信号
			{
				DI_STU stu = {i,iAlarmValue};
				XFStrategy &resStg = KgGlobalData::ms_resStrategy[3];
				resStg.diList.append(stu);
				int retNo = iStrategy - 50;
				initResAlarm(i, retNo, resStg, strDIName, strDIOverName);
			}
			else if (55 == iStrategy)	// 55:备用信号
			{
				DI_STU stu = {i,iAlarmValue};
				XFStrategy &resStg = KgGlobalData::ms_resStrategy[4];
				resStg.diList.append(stu);
				int retNo = iStrategy - 50;
				initResAlarm(i, retNo, resStg, strDIName, strDIOverName);
			}
			else if (56 == iStrategy)	// 56:备用信号
			{
				DI_STU stu = {i,iAlarmValue};
				XFStrategy &resStg = KgGlobalData::ms_resStrategy[5];
				resStg.diList.append(stu);
				int retNo = iStrategy - 50;
				initResAlarm(i, retNo, resStg, strDIName, strDIOverName);
			}
			else if (57 == iStrategy)	// 57:备用信号
			{
				DI_STU stu = {i,iAlarmValue};
				XFStrategy &resStg = KgGlobalData::ms_resStrategy[6];
				resStg.diList.append(stu);
				int retNo = iStrategy - 50;
				initResAlarm(i, retNo, resStg, strDIName, strDIOverName);
			}
			else if (58 == iStrategy)	// 58:备用信号
			{
				DI_STU stu = {i,iAlarmValue};
				XFStrategy &resStg = KgGlobalData::ms_resStrategy[7];
				resStg.diList.append(stu);
				int retNo = iStrategy - 50;
				initResAlarm(i, retNo, resStg, strDIName, strDIOverName);
			}
			else
				;
		}
	}

	KgGlobalData::ms_bcDiList.clear();
	for(i = 0; i <	KgGlobalData::ms_bcDiCount; ++i)// added 2024-8-28
	{
		int iStrategy = setApp.value(QString("BCDIColl/DI%1Strategy").arg(i+1),"0").toInt();
		int iAlarmValue = setApp.value(QString("BCDIColl/DI%1AlarmValue").arg(i+1),"1").toInt(); 
		//QString strDIName = setApp.value(QString("BCDIColl/DI%1Name").arg(i+1),"").toString(); 
		//QString strDIOverName = setApp.value(QString("BCDIColl/DI%1OverName").arg(i+1),"").toString(); 
		QString strDIName;
		QString strDIOverName;
		if(isChLang()) 
		{
			strDIName = setApp.value(QString("BCDIColl/DI%1Name").arg(i+1),"").toString(); 
			strDIOverName = setApp.value(QString("BCDIColl/DI%1OverName").arg(i+1),"").toString();
		}
		else
		{
			strDIName = setApp.value(QString("BCDIColl/DI%1NameEng").arg(i+1),"").toString(); 
			strDIOverName = setApp.value(QString("BCDIColl/DI%1OverNameEng").arg(i+1),"").toString();
		}

		if(strDIName.length() > 3)
		{
			writeKgLogfile(QString("*****BCDIColl DI%1Name:%2, DI%3OverName:%4.")
				.arg(i+1).arg(strDIName).arg(i+1).arg(strDIOverName));
		}
		
		if (iStrategy > 0)
		{
		    if (9 == iStrategy)// 9:消防采集干结点 
			{
				if(KgGlobalData::ms_xfStrategy.diList.count() > 0)
				{
					QString strLog = QString("*********BC DI%1 iStrategy:%2, iAlarmValue:%3(error:conflicted).").arg(i+1).arg(iStrategy).arg(iAlarmValue);
			        writeKgBcLogfile(strLog, true);
					continue;
				}
			}
			else if (10 == iStrategy)// 10:水浸采集干结点 
			{
			    if(KgGlobalData::ms_waterStrategy.diList.count() > 0)
				{
					QString strLog = QString("*********BC DI%1 iStrategy:%2, iAlarmValue:%3(error:conflicted).").arg(i+1).arg(iStrategy).arg(iAlarmValue);
			        writeKgBcLogfile(strLog, true);
					continue;
				}
			}
			else if(11 == iStrategy || 111 == iStrategy)
			{
				int count = KgGlobalData::ms_emgStopStrategy.diList.count() +  KgGlobalData::ms_emgStopStrategySec.diList.count();
				if(count > 0)
				{
					QString strLog = QString("*********BC DI%1 iStrategy:%2, iAlarmValue:%3(error:conflicted).").arg(i+1).arg(iStrategy).arg(iAlarmValue);
			        writeKgBcLogfile(strLog, true);
					continue;
				}
			}
			else if (24 == iStrategy)	// 24:门禁告警信号
			{
				if(KgGlobalData::ms_doorAlmStrategy.diList.count() > 0)
				{
					QString strLog = QString("*********BC DI%1 iStrategy:%2, iAlarmValue:%3(error:conflicted).").arg(i+1).arg(iStrategy).arg(iAlarmValue);
			        writeKgBcLogfile(strLog, true);
					continue;
				}
			}
			else if (25 == iStrategy)	// 25:消防喷洒信号 added 2022-12-10
			{
			    if(KgGlobalData::ms_xfSprayStrategy.diList.count() > 0)
				{
					QString strLog = QString("*********BC DI%1 iStrategy:%2, iAlarmValue:%3(error:conflicted).").arg(i+1).arg(iStrategy).arg(iAlarmValue);
			        writeKgBcLogfile(strLog, true);
					continue;
				}
			}
			else if (26 == iStrategy)	// 26:消防故障 added 2022-12-21
			{
				if(KgGlobalData::ms_xfFaultStrategy.diList.count() > 0)
				{
					QString strLog = QString("*********BC DI%1 iStrategy:%2, iAlarmValue:%3(error:conflicted).").arg(i+1).arg(iStrategy).arg(iAlarmValue);
			        writeKgBcLogfile(strLog, true);
					continue;
				}
			}
			else
				;
	 
			QString strLog = QString("*********BC DI%1 iStrategy:%2, iAlarmValue:%3.").arg(i+1).arg(iStrategy).arg(iAlarmValue);
			writeKgBcLogfile(strLog, true);

			if(iStrategy >= 51 && iStrategy <= 58)
			{
			    int resNo = iStrategy - 51 + 1;
				if(strDIName.length() >= 3)// 有指定告警发生名称 // added 2023-8-22
				{
					strDIName = parseDIName(strDIName);// + QString("(DI%1).").arg(diIndex+0);
					if(strDIOverName.length() >= 3)// 有指定告警结束名称 // added 2023-8-23
					{
						strDIOverName = parseDIName(strDIOverName) + QString(".");
					}
					else
					{
						strDIOverName = parseDIName(strDIName) + getOverName() + QString(".");
					}
				}
				else
				{
				    if(isChLang())
				    {
						strDIName = kgConvert("%1#备用告警").arg(resNo);
						strDIOverName = kgConvert("%1#备用告警结束.").arg(resNo);
				    }
					else
					{
					   strDIName = QString("%1# resvered alarm").arg(resNo);
					   strDIOverName = QString("%1# resvered alarm is over.").arg(resNo);
					}
				}

				DI_STU diItem = {i,iAlarmValue,iStrategy,strDIName, strDIOverName};
			    KgGlobalData::ms_bcDiList.append(diItem); 
			}
			else
			{			
				DI_STU diItem = {i,iAlarmValue,iStrategy,parseDIName(strDIName), parseDIName(strDIOverName)};
				KgGlobalData::ms_bcDiList.append(diItem);
			}
		}
	}
	
    KgGlobalData::ms_bcDoList.clear();
	int stg102Count = 0;
	int stg103_109Count = 0;
	for(i = 0; i <	KgGlobalData::ms_bcDoCount; ++i) // read DO Strategy
	{
		int iStrategy = setApp.value(QString("BCDOCtrl/DO%1Strategy").arg(i+1),"0").toInt();
		if (iStrategy > 0)
		{
			if(102 == iStrategy)
			{
				if(stg102Count > 0)
				{
					continue; // 102策略只能有1个
				}
				stg102Count += 1;
			}
			
			if(103 == iStrategy || 109 == iStrategy || 110 == iStrategy)
			{
				if(stg103_109Count > 0)
				{
					continue; // 103 109 110策略只能有1个
				}
				stg103_109Count += 1;
			}

			QString strLog = QString("*********BC DO%1 iStrategy:%2.").arg(i+1).arg(iStrategy);
			writeKgBcLogfile(strLog, true);
			
		    DOStrategy doStg = {i,iStrategy};
		    KgGlobalData::ms_bcDoList.append(doStg);
		}
	}
	
}

QString getAppVer()
{
	QString strVer = QString("V%1.%2.%3").arg(APP_VERSION_MAJOR).arg(APP_VERSION_MIDDLE).arg(APP_VERSION_MINOR);
	return strVer;
}

void printDiDoState()
{
	CIOModule *pIOModule = ::getIOModule();
	QString strLog = QString("DI1to3(XfAlm,XfMot,XfErr):%1-%2-%3, DI4to13(CDLQ):%4-%5-%6-%7-%8-%9-%10-%11-%12-%13, DI14to16(ZDLQ):%14-%15-%16")
		.arg(pIOModule->usDI[0]).arg(pIOModule->usDI[1]).arg(pIOModule->usDI[2]).arg(pIOModule->usDI[3])
		.arg(pIOModule->usDI[4]).arg(pIOModule->usDI[5]).arg(pIOModule->usDI[6]).arg(pIOModule->usDI[7])
		.arg(pIOModule->usDI[8]).arg(pIOModule->usDI[9]).arg(pIOModule->usDI[10]).arg(pIOModule->usDI[11])
		.arg(pIOModule->usDI[12]).arg(pIOModule->usDI[13]).arg(pIOModule->usDI[14]).arg(pIOModule->usDI[15]);
	writeKgLogfile(strLog);

	strLog = QString("DO1(FZ):%1,  Do2to11(PCS error node):%2-%3-%4-%5-%6-%7-%8-%9-%10-%11, DO12(Error lamp):%12")
		.arg(pIOModule->usDOState[0]).arg(pIOModule->usDOState[1]).arg(pIOModule->usDOState[2]).arg(pIOModule->usDOState[3])
		.arg(pIOModule->usDOState[4]).arg(pIOModule->usDOState[5]).arg(pIOModule->usDOState[6]).arg(pIOModule->usDOState[7])
		.arg(pIOModule->usDOState[8]).arg(pIOModule->usDOState[9]).arg(pIOModule->usDOState[10]).arg(pIOModule->usDOState[11]);
	writeKgLogfile(strLog);
}

CIOModule * getIOModule()
{
   return KgGlobalData::ms_pIOModule;
}

QString kgConvert(char *str) // added 2024-1-3
{
	return QString::fromLocal8Bit(str);
}
bool isFaultTkEnabled(CBattBank *pBank)
{
	bool ret = false;
	//if(KgGlobalData::ms_faultTkEnabled > 0 && fabs(pBank->fBankCur) > 5)
	{
		ret = true;
	}
	return ret;
}
bool isEmgTkEnabled()
{
	bool ret = false;
	//if(KgGlobalData::ms_emgTkEnabled > 0)
	{
		ret = true;
	}
	return ret;
}


